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