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 // TODO: Better check
765 if (t != type && list.Any (l => l.DeclaringType != method.DeclaringType && l.Name == method.Name && l.Parameters.Count == method.Parameters.Count))
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 static bool IsFinalizer (MethodDefinition method)
789 if (method.Name != "Finalize")
792 if (!method.IsVirtual)
795 if (method.Parameters.Count != 0)
801 private MethodDefinition [] GetConstructors (TypeDefinition type)
803 ArrayList list = new ArrayList ();
805 var ctors = type.Methods.Where (m => m.IsConstructor);//type.GetConstructors (flags);
806 foreach (MethodDefinition constructor in ctors) {
807 // we're only interested in public or protected members
808 if (!MustDocumentMethod(constructor))
811 list.Add (constructor);
814 return (MethodDefinition []) list.ToArray (typeof (MethodDefinition));
817 private EventDefinition[] GetEvents (TypeDefinition type)
819 ArrayList list = new ArrayList ();
821 var events = type.Events;//type.GetEvents (flags);
822 foreach (EventDefinition eventDef in events) {
823 MethodDefinition addMethod = eventDef.AddMethod;//eventInfo.GetAddMethod (true);
825 if (addMethod == null || !MustDocumentMethod (addMethod))
831 return (EventDefinition []) list.ToArray (typeof (EventDefinition));
835 class FieldData : MemberData
837 public FieldData (XmlWriter writer, FieldDefinition [] members)
838 : base (writer, members)
842 protected override string GetName (MemberReference memberDefenition)
844 FieldDefinition field = (FieldDefinition) memberDefenition;
848 protected override string GetMemberAttributes (MemberReference memberDefenition)
850 FieldDefinition field = (FieldDefinition) memberDefenition;
851 return ((int) field.Attributes).ToString (CultureInfo.InvariantCulture);
854 protected override void AddExtraAttributes (MemberReference memberDefinition)
856 base.AddExtraAttributes (memberDefinition);
858 FieldDefinition field = (FieldDefinition) memberDefinition;
859 AddAttribute ("fieldtype", Utils.CleanupTypeName (field.FieldType));
861 if (field.IsLiteral) {
862 object value = field.Constant;//object value = field.GetValue (null);
863 string stringValue = null;
864 //if (value is Enum) {
865 // // FIXME: when Mono bug #60090 has been
866 // // fixed, we should just be able to use
867 // // Convert.ToString
868 // stringValue = ((Enum) value).ToString ("D", CultureInfo.InvariantCulture);
871 stringValue = Convert.ToString (value, CultureInfo.InvariantCulture);
874 if (stringValue != null)
875 AddAttribute ("value", stringValue);
879 public override string ParentTag {
880 get { return "fields"; }
883 public override string Tag {
884 get { return "field"; }
888 class PropertyData : MemberData
890 public PropertyData (XmlWriter writer, PropertyDefinition [] members)
891 : base (writer, members)
895 protected override string GetName (MemberReference memberDefenition)
897 PropertyDefinition prop = (PropertyDefinition) memberDefenition;
901 MethodDefinition [] GetMethods (PropertyDefinition prop, out bool haveParameters)
903 MethodDefinition _get = prop.GetMethod;
904 MethodDefinition _set = prop.SetMethod;
905 bool haveGet = (_get != null && TypeData.MustDocumentMethod(_get));
906 bool haveSet = (_set != null && TypeData.MustDocumentMethod(_set));
907 haveParameters = haveGet || (haveSet && _set.Parameters.Count > 1);
908 MethodDefinition [] methods;
910 if (haveGet && haveSet) {
911 methods = new MethodDefinition [] { _get, _set };
912 } else if (haveGet) {
913 methods = new MethodDefinition [] { _get };
914 } else if (haveSet) {
915 methods = new MethodDefinition [] { _set };
924 protected override void AddExtraAttributes (MemberReference memberDefinition)
926 base.AddExtraAttributes (memberDefinition);
928 PropertyDefinition prop = (PropertyDefinition) memberDefinition;
929 AddAttribute ("ptype", Utils.CleanupTypeName (prop.PropertyType));
932 MethodDefinition [] methods = GetMethods ((PropertyDefinition) memberDefinition, out haveParameters);
934 if (methods != null && haveParameters) {
935 string parms = Parameters.GetSignature (methods [0].Parameters);
936 if (!string.IsNullOrEmpty (parms))
937 AddAttribute ("params", parms);
942 protected override void AddExtraData (MemberReference memberDefenition)
944 base.AddExtraData (memberDefenition);
947 MethodDefinition [] methods = GetMethods ((PropertyDefinition) memberDefenition, out haveParameters);
952 MethodData data = new MethodData (writer, methods);
953 //data.NoMemberAttributes = true;
957 protected override string GetMemberAttributes (MemberReference memberDefenition)
959 PropertyDefinition prop = (PropertyDefinition) memberDefenition;
960 return ((int) prop.Attributes).ToString (CultureInfo.InvariantCulture);
963 public override string ParentTag {
964 get { return "properties"; }
967 public override string Tag {
968 get { return "property"; }
972 class EventData : MemberData
974 public EventData (XmlWriter writer, EventDefinition [] members)
975 : base (writer, members)
979 protected override string GetName (MemberReference memberDefenition)
981 EventDefinition evt = (EventDefinition) memberDefenition;
985 protected override string GetMemberAttributes (MemberReference memberDefenition)
987 EventDefinition evt = (EventDefinition) memberDefenition;
988 return ((int) evt.Attributes).ToString (CultureInfo.InvariantCulture);
991 protected override void AddExtraAttributes (MemberReference memberDefinition)
993 base.AddExtraAttributes (memberDefinition);
995 EventDefinition evt = (EventDefinition) memberDefinition;
996 AddAttribute ("eventtype", Utils.CleanupTypeName (evt.EventType));
999 public override string ParentTag {
1000 get { return "events"; }
1003 public override string Tag {
1004 get { return "event"; }
1008 class MethodData : MemberData
1012 public MethodData (XmlWriter writer, MethodDefinition [] members)
1013 : base (writer, members)
1017 protected override string GetName (MemberReference memberDefenition)
1019 MethodDefinition method = (MethodDefinition) memberDefenition;
1020 string name = method.Name;
1021 string parms = Parameters.GetSignature (method.Parameters);
1023 return string.Format ("{0}({1})", name, parms);
1026 protected override string GetMemberAttributes (MemberReference memberDefenition)
1028 MethodDefinition method = (MethodDefinition) memberDefenition;
1029 return ((int)( method.Attributes)).ToString (CultureInfo.InvariantCulture);
1032 protected override ICustomAttributeProvider GetAdditionalCustomAttributeProvider (MemberReference member)
1034 var mbase = (MethodDefinition) member;
1035 return mbase.MethodReturnType;
1038 protected override void AddExtraAttributes (MemberReference memberDefinition)
1040 base.AddExtraAttributes (memberDefinition);
1042 if (!(memberDefinition is MethodDefinition))
1045 MethodDefinition mbase = (MethodDefinition) memberDefinition;
1047 if (mbase.IsAbstract)
1048 AddAttribute ("abstract", "true");
1049 if (mbase.IsVirtual)
1050 AddAttribute ("virtual", "true");
1051 if (mbase.IsFinal && mbase.IsVirtual && mbase.IsReuseSlot)
1052 AddAttribute ("sealed", "true");
1054 AddAttribute ("static", "true");
1055 var baseMethod = TypeHelper.GetBaseMethodInTypeHierarchy (mbase);
1056 if (baseMethod != null && baseMethod != mbase) {
1057 // This indicates whether this method is an override of another method.
1058 // This information is not necessarily available in the api info for any
1059 // particular assembly, because a method is only overriding another if
1060 // there is a base virtual function with the same signature, and that
1061 // base method can come from another assembly.
1062 AddAttribute ("is-override", "true");
1064 string rettype = Utils.CleanupTypeName (mbase.MethodReturnType.ReturnType);
1065 if (rettype != "System.Void" || !mbase.IsConstructor)
1066 AddAttribute ("returntype", (rettype));
1068 // if (mbase.MethodReturnType.HasCustomAttributes)
1069 // AttributeData.OutputAttributes (writer, mbase.MethodReturnType);
1072 protected override void AddExtraData (MemberReference memberDefenition)
1074 base.AddExtraData (memberDefenition);
1076 if (!(memberDefenition is MethodDefinition))
1079 MethodDefinition mbase = (MethodDefinition) memberDefenition;
1081 ParameterData parms = new ParameterData (writer, mbase.Parameters);
1084 MemberData.OutputGenericParameters (writer, mbase);
1087 public override bool NoMemberAttributes {
1088 get { return noAtts; }
1089 set { noAtts = value; }
1092 public override string ParentTag {
1093 get { return "methods"; }
1096 public override string Tag {
1097 get { return "method"; }
1101 class ConstructorData : MethodData
1103 public ConstructorData (XmlWriter writer, MethodDefinition [] members)
1104 : base (writer, members)
1108 public override string ParentTag {
1109 get { return "constructors"; }
1112 public override string Tag {
1113 get { return "constructor"; }
1117 class ParameterData : BaseData
1119 private IList<ParameterDefinition> parameters;
1121 public ParameterData (XmlWriter writer, IList<ParameterDefinition> parameters)
1124 this.parameters = parameters;
1127 public override void DoOutput ()
1129 writer.WriteStartElement ("parameters");
1130 foreach (ParameterDefinition parameter in parameters) {
1131 writer.WriteStartElement ("parameter");
1132 AddAttribute ("name", parameter.Name);
1133 AddAttribute ("position", parameter.Method.Parameters.IndexOf(parameter).ToString(CultureInfo.InvariantCulture));
1134 AddAttribute ("attrib", ((int) parameter.Attributes).ToString());
1136 string direction = "in";
1138 if (parameter.ParameterType is ByReferenceType)
1139 direction = parameter.IsOut ? "out" : "ref";
1141 TypeReference t = parameter.ParameterType;
1142 AddAttribute ("type", Utils.CleanupTypeName (t));
1144 if (parameter.IsOptional) {
1145 AddAttribute ("optional", "true");
1146 if (parameter.HasConstant)
1147 AddAttribute ("defaultValue", parameter.Constant == null ? "NULL" : parameter.Constant.ToString ());
1150 if (direction != "in")
1151 AddAttribute ("direction", direction);
1153 AttributeData.OutputAttributes (writer, parameter);
1154 writer.WriteEndElement (); // parameter
1156 writer.WriteEndElement (); // parameters
1162 public static void DoOutput (XmlWriter writer, IList<ICustomAttributeProvider> providers)
1165 throw new InvalidOperationException ("Document not set");
1167 if (providers == null || providers.Count == 0)
1170 if (!providers.Any ((provider) => provider != null && provider.HasCustomAttributes))
1173 writer.WriteStartElement ("attributes");
1175 foreach (var provider in providers) {
1176 if (provider == null)
1179 if (!provider.HasCustomAttributes)
1183 var ass = provider as AssemblyDefinition;
1184 if (ass != null && !Driver.FollowForwarders)
1185 TypeForwardedToData.OutputForwarders (writer, ass);
1187 var attributes = provider.CustomAttributes.
1188 Where ((att) => !SkipAttribute (att)).
1189 OrderBy ((a) => a.Constructor.DeclaringType.FullName, StringComparer.Ordinal);
1191 foreach (var att in attributes) {
1192 string attName = Utils.CleanupTypeName (att.Constructor.DeclaringType);
1194 writer.WriteStartElement ("attribute");
1195 writer.WriteAttributeString ("name", attName);
1197 var attribute_mapping = CreateAttributeMapping (att);
1199 if (attribute_mapping != null) {
1200 var mapping = attribute_mapping.Where ((attr) => attr.Key != "TypeId");
1201 if (mapping.Any ()) {
1202 writer.WriteStartElement ("properties");
1203 foreach (var kvp in mapping) {
1204 string name = kvp.Key;
1205 object o = kvp.Value;
1207 writer.WriteStartElement ("property");
1208 writer.WriteAttributeString ("name", name);
1211 writer.WriteAttributeString ("value", "null");
1213 string value = o.ToString ();
1214 if (attName.EndsWith ("GuidAttribute", StringComparison.Ordinal))
1215 value = value.ToUpper ();
1216 writer.WriteAttributeString ("value", value);
1219 writer.WriteEndElement (); // property
1221 writer.WriteEndElement (); // properties
1224 writer.WriteEndElement (); // attribute
1228 writer.WriteEndElement (); // attributes
1231 static Dictionary<string, object> CreateAttributeMapping (CustomAttribute attribute)
1233 Dictionary<string, object> mapping = null;
1235 PopulateMapping (ref mapping, attribute);
1237 var constructor = attribute.Constructor.Resolve ();
1238 if (constructor == null || !constructor.HasParameters)
1241 PopulateMapping (ref mapping, constructor, attribute);
1246 static void PopulateMapping (ref Dictionary<string, object> mapping, CustomAttribute attribute)
1248 if (!attribute.HasProperties)
1251 foreach (var named_argument in attribute.Properties) {
1252 var name = named_argument.Name;
1253 var arg = named_argument.Argument;
1255 if (arg.Value is CustomAttributeArgument)
1256 arg = (CustomAttributeArgument) arg.Value;
1258 if (mapping == null)
1259 mapping = new Dictionary<string, object> (StringComparer.Ordinal);
1260 mapping.Add (name, GetArgumentValue (arg.Type, arg.Value));
1264 static Dictionary<FieldReference, int> CreateArgumentFieldMapping (MethodDefinition constructor)
1266 Dictionary<FieldReference, int> field_mapping = null;
1268 int? argument = null;
1270 foreach (Instruction instruction in constructor.Body.Instructions) {
1271 switch (instruction.OpCode.Code) {
1283 argument = ((ParameterDefinition) instruction.Operand).Index + 1;
1287 FieldReference field = (FieldReference) instruction.Operand;
1288 if (field.DeclaringType.FullName != constructor.DeclaringType.FullName)
1291 if (!argument.HasValue)
1294 if (field_mapping == null)
1295 field_mapping = new Dictionary<FieldReference, int> ();
1297 if (!field_mapping.ContainsKey (field))
1298 field_mapping.Add (field, (int) argument - 1);
1305 return field_mapping;
1308 static Dictionary<PropertyDefinition, FieldReference> CreatePropertyFieldMapping (TypeDefinition type)
1310 Dictionary<PropertyDefinition, FieldReference> property_mapping = null;
1312 foreach (PropertyDefinition property in type.Properties) {
1313 if (property.GetMethod == null)
1315 if (!property.GetMethod.HasBody)
1318 foreach (Instruction instruction in property.GetMethod.Body.Instructions) {
1319 if (instruction.OpCode.Code != Code.Ldfld)
1322 FieldReference field = (FieldReference) instruction.Operand;
1323 if (field.DeclaringType.FullName != type.FullName)
1326 if (property_mapping == null)
1327 property_mapping = new Dictionary<PropertyDefinition, FieldReference> ();
1328 property_mapping.Add (property, field);
1333 return property_mapping;
1336 static void PopulateMapping (ref Dictionary<string, object> mapping, MethodDefinition constructor, CustomAttribute attribute)
1338 if (!constructor.HasBody)
1341 // Custom handling for attributes with arguments which cannot be easily extracted
1342 var ca = attribute.ConstructorArguments;
1343 switch (constructor.DeclaringType.FullName) {
1344 case "System.Runtime.CompilerServices.DecimalConstantAttribute":
1345 var dca = constructor.Parameters[2].ParameterType == constructor.Module.TypeSystem.Int32 ?
1346 new DecimalConstantAttribute ((byte) ca[0].Value, (byte) ca[1].Value, (int) ca[2].Value, (int) ca[3].Value, (int) ca[4].Value) :
1347 new DecimalConstantAttribute ((byte) ca[0].Value, (byte) ca[1].Value, (uint) ca[2].Value, (uint) ca[3].Value, (uint) ca[4].Value);
1349 if (mapping == null)
1350 mapping = new Dictionary<string, object> (StringComparer.Ordinal);
1351 mapping.Add ("Value", dca.Value);
1353 case "System.ComponentModel.BindableAttribute":
1357 if (constructor.Parameters[0].ParameterType == constructor.Module.TypeSystem.Boolean) {
1358 if (mapping == null)
1359 mapping = new Dictionary<string, object> (StringComparer.Ordinal);
1360 mapping.Add ("Bindable", ca[0].Value);
1362 throw new NotImplementedException ();
1368 var field_mapping = CreateArgumentFieldMapping (constructor);
1369 if (field_mapping != null) {
1370 var property_mapping = CreatePropertyFieldMapping ((TypeDefinition) constructor.DeclaringType);
1372 if (property_mapping != null) {
1373 foreach (var pair in property_mapping) {
1375 if (!field_mapping.TryGetValue (pair.Value, out argument))
1378 var ca_arg = ca [argument];
1379 if (ca_arg.Value is CustomAttributeArgument)
1380 ca_arg = (CustomAttributeArgument)ca_arg.Value;
1382 if (mapping == null)
1383 mapping = new Dictionary<string, object> (StringComparer.Ordinal);
1384 mapping.Add (pair.Key.Name, GetArgumentValue (ca_arg.Type, ca_arg.Value));
1390 static object GetArgumentValue (TypeReference reference, object value)
1392 var type = reference.Resolve ();
1397 if (IsFlaggedEnum (type))
1398 return GetFlaggedEnumValue (type, value);
1400 return GetEnumValue (type, value);
1406 static bool IsFlaggedEnum (TypeDefinition type)
1411 if (!type.HasCustomAttributes)
1414 foreach (CustomAttribute attribute in type.CustomAttributes)
1415 if (attribute.Constructor.DeclaringType.FullName == "System.FlagsAttribute")
1421 static object GetFlaggedEnumValue (TypeDefinition type, object value)
1424 return GetFlaggedEnumValue (type, (ulong)value);
1426 long flags = Convert.ToInt64 (value);
1427 var signature = new StringBuilder ();
1429 for (int i = type.Fields.Count - 1; i >= 0; i--) {
1430 FieldDefinition field = type.Fields [i];
1432 if (!field.HasConstant)
1435 long flag = Convert.ToInt64 (field.Constant);
1440 if ((flags & flag) == flag) {
1441 if (signature.Length != 0)
1442 signature.Append (", ");
1444 signature.Append (field.Name);
1449 return signature.ToString ();
1452 static object GetFlaggedEnumValue (TypeDefinition type, ulong flags)
1454 var signature = new StringBuilder ();
1456 for (int i = type.Fields.Count - 1; i >= 0; i--) {
1457 FieldDefinition field = type.Fields [i];
1459 if (!field.HasConstant)
1462 ulong flag = Convert.ToUInt64 (field.Constant);
1467 if ((flags & flag) == flag) {
1468 if (signature.Length != 0)
1469 signature.Append (", ");
1471 signature.Append (field.Name);
1476 return signature.ToString ();
1479 static object GetEnumValue (TypeDefinition type, object value)
1481 foreach (FieldDefinition field in type.Fields) {
1482 if (!field.HasConstant)
1485 if (Comparer.Default.Compare (field.Constant, value) == 0)
1492 static bool SkipAttribute (CustomAttribute attribute)
1494 if (!TypeHelper.IsPublic (attribute))
1497 return attribute.Constructor.DeclaringType.Name.EndsWith ("TODOAttribute", StringComparison.Ordinal);
1500 public static void OutputAttributes (XmlWriter writer, params ICustomAttributeProvider[] providers)
1502 AttributeData.DoOutput (writer, providers);
1506 static class Parameters {
1508 public static string GetSignature (IList<ParameterDefinition> infos)
1510 if (infos == null || infos.Count == 0)
1511 return string.Empty;
1513 var signature = new StringBuilder ();
1514 for (int i = 0; i < infos.Count; i++) {
1517 signature.Append (", ");
1519 ParameterDefinition info = infos [i];
1522 if ((info.Attributes & ParameterAttributes.In) != 0)
1524 else if ((info.Attributes & ParameterAttributes.Out) != 0)
1527 modifier = string.Empty;
1529 if (modifier.Length > 0) {
1530 signature.Append (modifier);
1531 signature.Append (" ");
1534 signature.Append (Utils.CleanupTypeName (info.ParameterType));
1537 return signature.ToString ();
1542 class TypeReferenceComparer : IComparer<TypeReference>
1544 public static TypeReferenceComparer Default = new TypeReferenceComparer ();
1546 public int Compare (TypeReference a, TypeReference b)
1548 int result = String.Compare (a.Namespace, b.Namespace, StringComparison.Ordinal);
1552 return String.Compare (a.Name, b.Name, StringComparison.Ordinal);
1556 class MemberReferenceComparer : IComparer
1558 public static MemberReferenceComparer Default = new MemberReferenceComparer ();
1560 public int Compare (object a, object b)
1562 MemberReference ma = (MemberReference) a;
1563 MemberReference mb = (MemberReference) b;
1564 return String.Compare (ma.Name, mb.Name, StringComparison.Ordinal);
1568 class PropertyDefinitionComparer : IComparer<PropertyDefinition>
1570 public static PropertyDefinitionComparer Default = new PropertyDefinitionComparer ();
1572 public int Compare (PropertyDefinition ma, PropertyDefinition mb)
1574 int res = String.Compare (ma.Name, mb.Name, StringComparison.Ordinal);
1578 if (!ma.HasParameters && !mb.HasParameters)
1581 if (!ma.HasParameters)
1584 if (!mb.HasParameters)
1587 return MethodDefinitionComparer.Compare (ma.Parameters, mb.Parameters);
1591 class MethodDefinitionComparer : IComparer
1593 public static MethodDefinitionComparer Default = new MethodDefinitionComparer ();
1595 public int Compare (object a, object b)
1597 MethodDefinition ma = (MethodDefinition) a;
1598 MethodDefinition mb = (MethodDefinition) b;
1599 int res = String.Compare (ma.Name, mb.Name, StringComparison.Ordinal);
1603 if (!ma.HasParameters && !mb.HasParameters)
1606 if (!ma.HasParameters)
1609 if (!mb.HasParameters)
1612 res = Compare (ma.Parameters, mb.Parameters);
1616 if (ma.HasGenericParameters != mb.HasGenericParameters)
1617 return ma.HasGenericParameters ? -1 : 1;
1619 if (ma.HasGenericParameters && mb.HasGenericParameters) {
1620 res = ma.GenericParameters.Count - mb.GenericParameters.Count;
1625 // operators can differ by only return type
1626 return string.CompareOrdinal (ma.ReturnType.FullName, mb.ReturnType.FullName);
1629 public static int Compare (IList<ParameterDefinition> pia, IList<ParameterDefinition> pib)
1631 var res = pia.Count - pib.Count;
1635 string siga = Parameters.GetSignature (pia);
1636 string sigb = Parameters.GetSignature (pib);
1637 return String.Compare (siga, sigb, StringComparison.Ordinal);