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
)
36 AssemblyCollection acoll
= new AssemblyCollection ();
38 string windir
= Environment
.GetFolderPath(Environment
.SpecialFolder
.Windows
);
39 string pf
= Environment
.GetFolderPath(Environment
.SpecialFolder
.ProgramFiles
);
40 TypeHelper
.Resolver
.AddSearchDirectory (Path
.Combine (windir
, @"assembly\GAC\MSDATASRC\7.0.3300.0__b03f5f7f11d50a3a"));
42 foreach (string arg
in args
) {
48 if (arg
.Contains ("v3.0")) {
49 TypeHelper
.Resolver
.AddSearchDirectory (Path
.Combine (windir
, @"Microsoft.NET\Framework\v2.0.50727"));
50 } else if (arg
.Contains ("v3.5")) {
51 TypeHelper
.Resolver
.AddSearchDirectory (Path
.Combine (windir
, @"Microsoft.NET\Framework\v2.0.50727"));
52 TypeHelper
.Resolver
.AddSearchDirectory (Path
.Combine (windir
, @"Microsoft.NET\Framework\v3.0\Windows Communication Foundation"));
53 } else if (arg
.Contains ("v4.0")) {
54 if (arg
.Contains ("Silverlight")) {
55 TypeHelper
.Resolver
.AddSearchDirectory (Path
.Combine (pf
, @"Microsoft Silverlight\4.0.51204.0"));
57 TypeHelper
.Resolver
.AddSearchDirectory (Path
.Combine (windir
, @"Microsoft.NET\Framework\v4.0.30319"));
58 TypeHelper
.Resolver
.AddSearchDirectory (Path
.Combine (windir
, @"Microsoft.NET\Framework\v4.0.30319\WPF"));
61 TypeHelper
.Resolver
.AddSearchDirectory (Path
.GetDirectoryName (arg
));
66 XmlDocument doc
= new XmlDocument ();
70 var writer
= new WellFormedXmlWriter (new XmlTextWriter (Console
.Out
) { Formatting = Formatting.Indented }
);
71 XmlNode decl
= doc
.CreateXmlDeclaration ("1.0", "utf-8", null);
72 doc
.InsertBefore (decl
, doc
.DocumentElement
);
77 internal static bool AbiMode { get; private set; }
82 public static string CleanupTypeName (TypeReference type
)
84 return CleanupTypeName (type
.FullName
);
87 public static string CleanupTypeName (string t
)
89 return t
.Replace ('<', '[').Replace ('>', ']').Replace ('/', '+');
93 class AssemblyCollection
96 List
<AssemblyDefinition
> assemblies
= new List
<AssemblyDefinition
> ();
98 public AssemblyCollection ()
102 public bool Add (string name
)
104 AssemblyDefinition ass
= LoadAssembly (name
);
106 Console
.Error
.WriteLine ("Cannot load assembly file " + name
);
110 assemblies
.Add (ass
);
114 public void DoOutput ()
116 if (document
== null)
117 throw new InvalidOperationException ("Document not set");
119 XmlNode nassemblies
= document
.CreateElement ("assemblies", null);
120 document
.AppendChild (nassemblies
);
121 foreach (AssemblyDefinition a
in assemblies
) {
122 AssemblyData data
= new AssemblyData (document
, nassemblies
, a
);
127 public XmlDocument Document
{
128 set { document = value; }
131 AssemblyDefinition
LoadAssembly (string assembly
)
134 if (File
.Exists (assembly
))
135 return TypeHelper
.Resolver
.ResolveFile (assembly
);
137 return TypeHelper
.Resolver
.Resolve (assembly
);
138 } catch (Exception e
) {
139 Console
.WriteLine (e
);
145 abstract class BaseData
147 protected XmlDocument document
;
148 protected XmlNode parent
;
150 protected BaseData (XmlDocument doc
, XmlNode parent
)
153 this.parent
= parent
;
156 public abstract void DoOutput ();
158 protected void AddAttribute (XmlNode node
, string name
, string value)
160 XmlAttribute attr
= document
.CreateAttribute (name
);
162 node
.Attributes
.Append (attr
);
166 class TypeForwardedToData
: BaseData
168 AssemblyDefinition ass
;
170 public TypeForwardedToData (XmlDocument document
, XmlNode parent
, AssemblyDefinition ass
)
171 : base (document
, parent
)
176 public override void DoOutput ()
178 XmlNode natts
= parent
.SelectSingleNode("attributes");
180 natts
= document
.CreateElement ("attributes", null);
181 parent
.AppendChild (natts
);
184 foreach (ExportedType type
in ass
.MainModule
.ExportedTypes
) {
186 if (((uint)type
.Attributes
& 0x200000u
) == 0)
189 XmlNode node
= document
.CreateElement ("attribute");
190 AddAttribute (node
, "name", typeof (TypeForwardedToAttribute
).FullName
);
191 XmlNode properties
= node
.AppendChild (document
.CreateElement ("properties"));
192 XmlNode property
= properties
.AppendChild (document
.CreateElement ("property"));
193 AddAttribute (property
, "name", "Destination");
194 AddAttribute (property
, "value", Utils
.CleanupTypeName (type
.FullName
));
195 natts
.AppendChild (node
);
199 public static void OutputForwarders (XmlDocument document
, XmlNode parent
, AssemblyDefinition ass
)
201 TypeForwardedToData tftd
= new TypeForwardedToData (document
, parent
, ass
);
206 class AssemblyData
: BaseData
208 AssemblyDefinition ass
;
210 public AssemblyData (XmlDocument document
, XmlNode parent
, AssemblyDefinition ass
)
211 : base (document
, parent
)
216 public override void DoOutput ()
218 if (document
== null)
219 throw new InvalidOperationException ("Document not set");
221 XmlNode nassembly
= document
.CreateElement ("assembly", null);
222 AssemblyNameDefinition aname
= ass
.Name
;
223 AddAttribute (nassembly
, "name", aname
.Name
);
224 AddAttribute (nassembly
, "version", aname
.Version
.ToString ());
225 parent
.AppendChild (nassembly
);
226 TypeForwardedToData
.OutputForwarders (document
, nassembly
, ass
);
227 AttributeData
.OutputAttributes (document
, nassembly
, ass
);
228 var typesCollection
= ass
.MainModule
.Types
;
229 if (typesCollection
== null || typesCollection
.Count
== 0)
231 var typesArray
= new TypeDefinition
[typesCollection
.Count
];
232 for (int i
= 0; i
< typesCollection
.Count
; i
++) {
233 typesArray
[i
] = typesCollection
[i
];
235 Array
.Sort (typesArray
, TypeReferenceComparer
.Default
);
237 XmlNode nss
= document
.CreateElement ("namespaces", null);
238 nassembly
.AppendChild (nss
);
240 string current_namespace
= "$%&$&";
242 XmlNode classes
= null;
243 foreach (TypeDefinition t
in typesArray
) {
244 if (string.IsNullOrEmpty (t
.Namespace
))
247 if (!Driver
.AbiMode
&& ((t
.Attributes
& TypeAttributes
.VisibilityMask
) != TypeAttributes
.Public
))
250 if (t
.DeclaringType
!= null)
251 continue; // enforce !nested
253 if (t
.Namespace
!= current_namespace
) {
254 current_namespace
= t
.Namespace
;
255 ns
= document
.CreateElement ("namespace", null);
256 AddAttribute (ns
, "name", current_namespace
);
257 nss
.AppendChild (ns
);
258 classes
= document
.CreateElement ("classes", null);
259 ns
.AppendChild (classes
);
262 TypeData bd
= new TypeData (document
, classes
, t
);
268 abstract class MemberData
: BaseData
270 MemberReference
[] members
;
272 public MemberData (XmlDocument document
, XmlNode parent
, MemberReference
[] members
)
273 : base (document
, parent
)
275 this.members
= members
;
278 public override void DoOutput ()
280 XmlNode mclass
= document
.CreateElement (ParentTag
, null);
281 parent
.AppendChild (mclass
);
283 foreach (MemberReference member
in members
) {
284 XmlNode mnode
= document
.CreateElement (Tag
, null);
285 mclass
.AppendChild (mnode
);
286 AddAttribute (mnode
, "name", GetName (member
));
287 if (!NoMemberAttributes
)
288 AddAttribute (mnode
, "attrib", GetMemberAttributes (member
));
290 AttributeData
.OutputAttributes (document
, mnode
, (ICustomAttributeProvider
) member
);
292 AddExtraData (mnode
, member
);
296 protected virtual void AddExtraData (XmlNode p
, MemberReference memberDefenition
)
300 protected virtual string GetName (MemberReference memberDefenition
)
305 protected virtual string GetMemberAttributes (MemberReference memberDefenition
)
310 public virtual bool NoMemberAttributes
{
311 get { return false; }
315 public virtual string ParentTag
{
316 get { return "NoPARENTTAG"; }
319 public virtual string Tag
{
320 get { return "NoTAG"; }
323 public static void OutputGenericParameters (XmlDocument document
, XmlNode nclass
, IGenericParameterProvider provider
)
325 if (provider
.GenericParameters
.Count
== 0)
328 var gparameters
= provider
.GenericParameters
;
330 XmlElement ngeneric
= document
.CreateElement ("generic-parameters");
331 nclass
.AppendChild (ngeneric
);
333 foreach (GenericParameter gp
in gparameters
) {
334 XmlElement nparam
= document
.CreateElement ("generic-parameter");
335 nparam
.SetAttribute ("name", gp
.Name
);
336 nparam
.SetAttribute ("attributes", ((int) gp
.Attributes
).ToString ());
338 AttributeData
.OutputAttributes (document
, nparam
, gp
);
340 ngeneric
.AppendChild (nparam
);
342 var constraints
= gp
.Constraints
;
343 if (constraints
.Count
== 0)
346 XmlElement nconstraint
= document
.CreateElement ("generic-parameter-constraints");
348 foreach (TypeReference constraint
in constraints
) {
349 XmlElement ncons
= document
.CreateElement ("generic-parameter-constraint");
350 ncons
.SetAttribute ("name", Utils
.CleanupTypeName (constraint
));
351 nconstraint
.AppendChild (ncons
);
354 nparam
.AppendChild (nconstraint
);
359 class TypeData
: MemberData
363 public TypeData (XmlDocument document
, XmlNode parent
, TypeDefinition type
)
364 : base (document
, parent
, null)
368 public override void DoOutput ()
370 if (document
== null)
371 throw new InvalidOperationException ("Document not set");
373 XmlNode nclass
= document
.CreateElement ("class", null);
374 AddAttribute (nclass
, "name", type
.Name
);
375 string classType
= GetClassType (type
);
376 AddAttribute (nclass
, "type", classType
);
378 if (type
.BaseType
!= null)
379 AddAttribute (nclass
, "base", Utils
.CleanupTypeName (type
.BaseType
));
382 AddAttribute (nclass
, "sealed", "true");
385 AddAttribute (nclass
, "abstract", "true");
387 if ( (type
.Attributes
& TypeAttributes
.Serializable
) != 0 || type
.IsEnum
)
388 AddAttribute (nclass
, "serializable", "true");
390 string charSet
= GetCharSet (type
);
391 AddAttribute (nclass
, "charset", charSet
);
393 string layout
= GetLayout (type
);
395 AddAttribute (nclass
, "layout", layout
);
397 if (type
.PackingSize
>= 0) {
398 AddAttribute (nclass
, "pack", type
.PackingSize
.ToString ());
401 if (type
.ClassSize
>= 0) {
402 AddAttribute (nclass
, "size", type
.ClassSize
.ToString ());
405 parent
.AppendChild (nclass
);
407 AttributeData
.OutputAttributes (document
, nclass
, type
);
409 XmlNode ifaces
= null;
411 foreach (TypeReference iface
in TypeHelper
.GetInterfaces (type
).OrderBy (s
=> s
.FullName
)) {
412 if (!TypeHelper
.IsPublic (iface
))
413 // we're only interested in public interfaces
416 if (ifaces
== null) {
417 ifaces
= document
.CreateElement ("interfaces", null);
418 nclass
.AppendChild (ifaces
);
421 XmlNode iface_node
= document
.CreateElement ("interface", null);
422 AddAttribute (iface_node
, "name", Utils
.CleanupTypeName (iface
));
423 ifaces
.AppendChild (iface_node
);
426 MemberData
.OutputGenericParameters (document
, nclass
, type
);
428 ArrayList members
= new ArrayList ();
430 FieldDefinition
[] fields
= GetFields (type
);
431 if (fields
.Length
> 0) {
432 Array
.Sort (fields
, MemberReferenceComparer
.Default
);
433 FieldData fd
= new FieldData (document
, nclass
, fields
);
438 var value_type
= GetEnumValueField (type
);
439 if (value_type
== null)
440 throw new NotSupportedException ();
442 AddAttribute (nclass
, "enumtype", Utils
.CleanupTypeName (value_type
.FieldType
));
445 if (!Driver
.AbiMode
) {
447 MethodDefinition
[] ctors
= GetConstructors (type
);
448 if (ctors
.Length
> 0) {
449 Array
.Sort (ctors
, MethodDefinitionComparer
.Default
);
450 members
.Add (new ConstructorData (document
, nclass
, ctors
));
453 PropertyDefinition
[] properties
= GetProperties (type
);
454 if (properties
.Length
> 0) {
455 Array
.Sort (properties
, MemberReferenceComparer
.Default
);
456 members
.Add (new PropertyData (document
, nclass
, properties
));
459 EventDefinition
[] events
= GetEvents (type
);
460 if (events
.Length
> 0) {
461 Array
.Sort (events
, MemberReferenceComparer
.Default
);
462 members
.Add (new EventData (document
, nclass
, events
));
465 MethodDefinition
[] methods
= GetMethods (type
);
466 if (methods
.Length
> 0) {
467 Array
.Sort (methods
, MethodDefinitionComparer
.Default
);
468 members
.Add (new MethodData (document
, nclass
, methods
));
472 foreach (MemberData md
in members
)
475 var nested
= type
.NestedTypes
;
476 //remove non public(familiy) and nested in second degree
477 for (int i
= nested
.Count
- 1; i
>= 0; i
--) {
478 TypeDefinition t
= nested
[i
];
479 if ((t
.Attributes
& TypeAttributes
.VisibilityMask
) == TypeAttributes
.NestedPublic
||
480 (t
.Attributes
& TypeAttributes
.VisibilityMask
) == TypeAttributes
.NestedFamily
||
481 (t
.Attributes
& TypeAttributes
.VisibilityMask
) == TypeAttributes
.NestedFamORAssem
) {
483 if (t
.DeclaringType
== type
)
484 continue; // not nested of nested
490 if (nested
.Count
> 0) {
491 var nestedArray
= nested
.ToArray ();
492 Array
.Sort (nestedArray
, TypeReferenceComparer
.Default
);
494 XmlNode classes
= document
.CreateElement ("classes", null);
495 nclass
.AppendChild (classes
);
496 foreach (TypeDefinition t
in nestedArray
) {
497 TypeData td
= new TypeData (document
, classes
, t
);
503 static FieldReference
GetEnumValueField (TypeDefinition type
)
505 foreach (FieldDefinition field
in type
.Fields
)
506 if (field
.IsSpecialName
&& field
.Name
== "value__")
512 protected override string GetMemberAttributes (MemberReference member
)
515 throw new InvalidOperationException ("odd");
517 return ((int) type
.Attributes
).ToString (CultureInfo
.InvariantCulture
);
520 public static bool MustDocumentMethod (MethodDefinition method
) {
522 MethodAttributes maskedAccess
= method
.Attributes
& MethodAttributes
.MemberAccessMask
;
523 return maskedAccess
== MethodAttributes
.Public
524 || maskedAccess
== MethodAttributes
.Family
525 || maskedAccess
== MethodAttributes
.FamORAssem
;
528 static string GetClassType (TypeDefinition t
)
539 if (TypeHelper
.IsDelegate(t
))
548 static string GetCharSet (TypeDefinition type
)
550 TypeAttributes maskedStringFormat
= type
.Attributes
& TypeAttributes
.StringFormatMask
;
551 if (maskedStringFormat
== TypeAttributes
.AnsiClass
)
552 return CharSet
.Ansi
.ToString ();
554 if (maskedStringFormat
== TypeAttributes
.AutoClass
)
555 return CharSet
.Auto
.ToString ();
557 if (maskedStringFormat
== TypeAttributes
.UnicodeClass
)
558 return CharSet
.Unicode
.ToString ();
560 return CharSet
.None
.ToString ();
563 static string GetLayout (TypeDefinition type
)
565 TypeAttributes maskedLayout
= type
.Attributes
& TypeAttributes
.LayoutMask
;
566 if (maskedLayout
== TypeAttributes
.AutoLayout
)
567 return LayoutKind
.Auto
.ToString ();
569 if (maskedLayout
== TypeAttributes
.ExplicitLayout
)
570 return LayoutKind
.Explicit
.ToString ();
572 if (maskedLayout
== TypeAttributes
.SequentialLayout
)
573 return LayoutKind
.Sequential
.ToString ();
578 FieldDefinition
[] GetFields (TypeDefinition type
) {
579 ArrayList list
= new ArrayList ();
581 var fields
= type
.Fields
;
582 foreach (FieldDefinition field
in fields
) {
583 if (field
.IsSpecialName
)
586 if (Driver
.AbiMode
&& field
.IsStatic
)
589 // we're only interested in public or protected members
590 FieldAttributes maskedVisibility
= (field
.Attributes
& FieldAttributes
.FieldAccessMask
);
591 if (Driver
.AbiMode
&& !field
.IsNotSerialized
) {
594 if (maskedVisibility
== FieldAttributes
.Public
595 || maskedVisibility
== FieldAttributes
.Family
596 || maskedVisibility
== FieldAttributes
.FamORAssem
) {
602 return (FieldDefinition
[]) list
.ToArray (typeof (FieldDefinition
));
606 internal static PropertyDefinition
[] GetProperties (TypeDefinition type
) {
607 ArrayList list
= new ArrayList ();
609 var properties
= type
.Properties
;//type.GetProperties (flags);
610 foreach (PropertyDefinition property
in properties
) {
611 MethodDefinition getMethod
= property
.GetMethod
;
612 MethodDefinition setMethod
= property
.SetMethod
;
614 bool hasGetter
= (getMethod
!= null) && MustDocumentMethod (getMethod
);
615 bool hasSetter
= (setMethod
!= null) && MustDocumentMethod (setMethod
);
617 // if neither the getter or setter should be documented, then
619 if (hasGetter
|| hasSetter
) {
624 return (PropertyDefinition
[]) list
.ToArray (typeof (PropertyDefinition
));
627 private MethodDefinition
[] GetMethods (TypeDefinition type
)
629 ArrayList list
= new ArrayList ();
631 var methods
= type
.Methods
;//type.GetMethods (flags);
632 foreach (MethodDefinition method
in methods
) {
633 if (method
.IsSpecialName
&& !method
.Name
.StartsWith ("op_"))
636 // we're only interested in public or protected members
637 if (!MustDocumentMethod(method
))
640 if (IsFinalizer (method
)) {
641 string name
= method
.DeclaringType
.Name
;
642 int arity
= name
.IndexOf ('`');
644 name
= name
.Substring (0, arity
);
646 method
.Name
= "~" + name
;
652 return (MethodDefinition
[]) list
.ToArray (typeof (MethodDefinition
));
655 static bool IsFinalizer (MethodDefinition method
)
657 if (method
.Name
!= "Finalize")
660 if (!method
.IsVirtual
)
663 if (method
.Parameters
.Count
!= 0)
669 private MethodDefinition
[] GetConstructors (TypeDefinition type
)
671 ArrayList list
= new ArrayList ();
673 var ctors
= type
.Methods
.Where (m
=> m
.IsConstructor
);//type.GetConstructors (flags);
674 foreach (MethodDefinition constructor
in ctors
) {
675 // we're only interested in public or protected members
676 if (!MustDocumentMethod(constructor
))
679 list
.Add (constructor
);
682 return (MethodDefinition
[]) list
.ToArray (typeof (MethodDefinition
));
685 private EventDefinition
[] GetEvents (TypeDefinition type
)
687 ArrayList list
= new ArrayList ();
689 var events
= type
.Events
;//type.GetEvents (flags);
690 foreach (EventDefinition eventDef
in events
) {
691 MethodDefinition addMethod
= eventDef
.AddMethod
;//eventInfo.GetAddMethod (true);
693 if (addMethod
== null || !MustDocumentMethod (addMethod
))
699 return (EventDefinition
[]) list
.ToArray (typeof (EventDefinition
));
703 class FieldData
: MemberData
705 public FieldData (XmlDocument document
, XmlNode parent
, FieldDefinition
[] members
)
706 : base (document
, parent
, members
)
710 protected override string GetName (MemberReference memberDefenition
)
712 FieldDefinition field
= (FieldDefinition
) memberDefenition
;
716 protected override string GetMemberAttributes (MemberReference memberDefenition
)
718 FieldDefinition field
= (FieldDefinition
) memberDefenition
;
719 return ((int) field
.Attributes
).ToString (CultureInfo
.InvariantCulture
);
722 protected override void AddExtraData (XmlNode p
, MemberReference memberDefenition
)
724 base.AddExtraData (p
, memberDefenition
);
725 FieldDefinition field
= (FieldDefinition
) memberDefenition
;
726 AddAttribute (p
, "fieldtype", Utils
.CleanupTypeName (field
.FieldType
));
728 if (field
.IsLiteral
) {
729 object value = field
.Constant
;//object value = field.GetValue (null);
730 string stringValue
= null;
731 //if (value is Enum) {
732 // // FIXME: when Mono bug #60090 has been
733 // // fixed, we should just be able to use
734 // // Convert.ToString
735 // stringValue = ((Enum) value).ToString ("D", CultureInfo.InvariantCulture);
738 stringValue
= Convert
.ToString (value, CultureInfo
.InvariantCulture
);
741 if (stringValue
!= null)
742 AddAttribute (p
, "value", stringValue
);
746 public override string ParentTag
{
747 get { return "fields"; }
750 public override string Tag
{
751 get { return "field"; }
755 class PropertyData
: MemberData
757 public PropertyData (XmlDocument document
, XmlNode parent
, PropertyDefinition
[] members
)
758 : base (document
, parent
, members
)
762 protected override string GetName (MemberReference memberDefenition
)
764 PropertyDefinition prop
= (PropertyDefinition
) memberDefenition
;
768 protected override void AddExtraData (XmlNode p
, MemberReference memberDefenition
)
770 base.AddExtraData (p
, memberDefenition
);
771 PropertyDefinition prop
= (PropertyDefinition
) memberDefenition
;
772 AddAttribute (p
, "ptype", Utils
.CleanupTypeName (prop
.PropertyType
));
773 MethodDefinition _get
= prop
.GetMethod
;
774 MethodDefinition _set
= prop
.SetMethod
;
775 bool haveGet
= (_get
!= null && TypeData
.MustDocumentMethod(_get
));
776 bool haveSet
= (_set
!= null && TypeData
.MustDocumentMethod(_set
));
777 MethodDefinition
[] methods
;
779 if (haveGet
&& haveSet
) {
780 methods
= new MethodDefinition
[] { _get, _set }
;
781 } else if (haveGet
) {
782 methods
= new MethodDefinition
[] { _get }
;
783 } else if (haveSet
) {
784 methods
= new MethodDefinition
[] { _set }
;
790 if (haveGet
|| _set
.Parameters
.Count
> 1) {
791 string parms
= Parameters
.GetSignature (methods
[0].Parameters
);
792 if (!string.IsNullOrEmpty (parms
))
793 AddAttribute (p
, "params", parms
);
796 MethodData data
= new MethodData (document
, p
, methods
);
797 //data.NoMemberAttributes = true;
801 protected override string GetMemberAttributes (MemberReference memberDefenition
)
803 PropertyDefinition prop
= (PropertyDefinition
) memberDefenition
;
804 return ((int) prop
.Attributes
).ToString (CultureInfo
.InvariantCulture
);
807 public override string ParentTag
{
808 get { return "properties"; }
811 public override string Tag
{
812 get { return "property"; }
816 class EventData
: MemberData
818 public EventData (XmlDocument document
, XmlNode parent
, EventDefinition
[] members
)
819 : base (document
, parent
, members
)
823 protected override string GetName (MemberReference memberDefenition
)
825 EventDefinition evt
= (EventDefinition
) memberDefenition
;
829 protected override string GetMemberAttributes (MemberReference memberDefenition
)
831 EventDefinition evt
= (EventDefinition
) memberDefenition
;
832 return ((int) evt
.Attributes
).ToString (CultureInfo
.InvariantCulture
);
835 protected override void AddExtraData (XmlNode p
, MemberReference memberDefenition
)
837 base.AddExtraData (p
, memberDefenition
);
838 EventDefinition evt
= (EventDefinition
) memberDefenition
;
839 AddAttribute (p
, "eventtype", Utils
.CleanupTypeName (evt
.EventType
));
842 public override string ParentTag
{
843 get { return "events"; }
846 public override string Tag
{
847 get { return "event"; }
851 class MethodData
: MemberData
855 public MethodData (XmlDocument document
, XmlNode parent
, MethodDefinition
[] members
)
856 : base (document
, parent
, members
)
860 protected override string GetName (MemberReference memberDefenition
)
862 MethodDefinition method
= (MethodDefinition
) memberDefenition
;
863 string name
= method
.Name
;
864 string parms
= Parameters
.GetSignature (method
.Parameters
);
866 return string.Format ("{0}({1})", name
, parms
);
869 protected override string GetMemberAttributes (MemberReference memberDefenition
)
871 MethodDefinition method
= (MethodDefinition
) memberDefenition
;
872 return ((int)( method
.Attributes
)).ToString (CultureInfo
.InvariantCulture
);
875 protected override void AddExtraData (XmlNode p
, MemberReference memberDefenition
)
877 base.AddExtraData (p
, memberDefenition
);
879 if (!(memberDefenition
is MethodDefinition
))
882 MethodDefinition mbase
= (MethodDefinition
) memberDefenition
;
884 ParameterData parms
= new ParameterData (document
, p
, mbase
.Parameters
);
887 if (mbase
.IsAbstract
)
888 AddAttribute (p
, "abstract", "true");
890 AddAttribute (p
, "virtual", "true");
891 if (mbase
.IsFinal
&& mbase
.IsVirtual
&& mbase
.IsReuseSlot
)
892 AddAttribute (p
, "sealed", "true");
894 AddAttribute (p
, "static", "true");
896 string rettype
= Utils
.CleanupTypeName (mbase
.MethodReturnType
.ReturnType
);
897 if (rettype
!= "System.Void" || !mbase
.IsConstructor
)
898 AddAttribute (p
, "returntype", (rettype
));
900 AttributeData
.OutputAttributes (document
, p
, mbase
.MethodReturnType
);
902 MemberData
.OutputGenericParameters (document
, p
, mbase
);
905 public override bool NoMemberAttributes
{
906 get { return noAtts; }
907 set { noAtts = value; }
910 public override string ParentTag
{
911 get { return "methods"; }
914 public override string Tag
{
915 get { return "method"; }
919 class ConstructorData
: MethodData
921 public ConstructorData (XmlDocument document
, XmlNode parent
, MethodDefinition
[] members
)
922 : base (document
, parent
, members
)
926 public override string ParentTag
{
927 get { return "constructors"; }
930 public override string Tag
{
931 get { return "constructor"; }
935 class ParameterData
: BaseData
937 private IList
<ParameterDefinition
> parameters
;
939 public ParameterData (XmlDocument document
, XmlNode parent
, IList
<ParameterDefinition
> parameters
)
940 : base (document
, parent
)
942 this.parameters
= parameters
;
945 public override void DoOutput ()
947 XmlNode parametersNode
= document
.CreateElement ("parameters");
948 parent
.AppendChild (parametersNode
);
950 foreach (ParameterDefinition parameter
in parameters
) {
951 XmlNode paramNode
= document
.CreateElement ("parameter");
952 parametersNode
.AppendChild (paramNode
);
953 AddAttribute (paramNode
, "name", parameter
.Name
);
954 AddAttribute (paramNode
, "position", parameter
.Method
.Parameters
.IndexOf(parameter
).ToString(CultureInfo
.InvariantCulture
));
955 AddAttribute (paramNode
, "attrib", ((int) parameter
.Attributes
).ToString());
957 string direction
= "in";
959 if (parameter
.ParameterType
is ByReferenceType
)
960 direction
= parameter
.IsOut
? "out" : "ref";
962 TypeReference t
= parameter
.ParameterType
;
963 AddAttribute (paramNode
, "type", Utils
.CleanupTypeName (t
));
965 if (parameter
.IsOptional
) {
966 AddAttribute (paramNode
, "optional", "true");
967 if (parameter
.HasConstant
)
968 AddAttribute (paramNode
, "defaultValue", parameter
.Constant
== null ? "NULL" : parameter
.Constant
.ToString ());
971 if (direction
!= "in")
972 AddAttribute (paramNode
, "direction", direction
);
974 AttributeData
.OutputAttributes (document
, paramNode
, parameter
);
979 class AttributeData
: BaseData
981 IList
<CustomAttribute
> atts
;
983 AttributeData (XmlDocument doc
, XmlNode parent
, IList
<CustomAttribute
> attributes
)
989 public override void DoOutput ()
991 if (document
== null)
992 throw new InvalidOperationException ("Document not set");
994 if (atts
== null || atts
.Count
== 0)
997 XmlNode natts
= parent
.SelectSingleNode("attributes");
999 natts
= document
.CreateElement ("attributes", null);
1000 parent
.AppendChild (natts
);
1003 for (int i
= 0; i
< atts
.Count
; ++i
) {
1004 CustomAttribute att
= atts
[i
];
1006 string attName
= Utils
.CleanupTypeName (att
.Constructor
.DeclaringType
);
1007 if (SkipAttribute (att
))
1010 XmlNode node
= document
.CreateElement ("attribute");
1011 AddAttribute (node
, "name", attName
);
1013 XmlNode properties
= null;
1015 Dictionary
<string, object> attribute_mapping
= CreateAttributeMapping (att
);
1017 foreach (string name
in attribute_mapping
.Keys
) {
1018 if (name
== "TypeId")
1021 if (properties
== null) {
1022 properties
= node
.AppendChild (document
.CreateElement ("properties"));
1025 object o
= attribute_mapping
[name
];
1027 XmlNode n
= properties
.AppendChild (document
.CreateElement ("property"));
1028 AddAttribute (n
, "name", name
);
1031 AddAttribute (n
, "value", "null");
1035 string value = o
.ToString ();
1036 if (attName
.EndsWith ("GuidAttribute"))
1037 value = value.ToUpper ();
1038 AddAttribute (n
, "value", value);
1041 natts
.AppendChild (node
);
1045 static Dictionary
<string, object> CreateAttributeMapping (CustomAttribute attribute
)
1047 var mapping
= new Dictionary
<string, object> ();
1049 PopulateMapping (mapping
, attribute
);
1051 var constructor
= attribute
.Constructor
.Resolve ();
1052 if (constructor
== null || !constructor
.HasParameters
)
1055 PopulateMapping (mapping
, constructor
, attribute
);
1060 static void PopulateMapping (Dictionary
<string, object> mapping
, CustomAttribute attribute
)
1062 if (!attribute
.HasProperties
)
1065 foreach (var named_argument
in attribute
.Properties
) {
1066 var name
= named_argument
.Name
;
1067 var arg
= named_argument
.Argument
;
1069 if (arg
.Value
is CustomAttributeArgument
)
1070 arg
= (CustomAttributeArgument
) arg
.Value
;
1072 mapping
.Add (name
, GetArgumentValue (arg
.Type
, arg
.Value
));
1076 static Dictionary
<FieldReference
, int> CreateArgumentFieldMapping (MethodDefinition constructor
)
1078 Dictionary
<FieldReference
, int> field_mapping
= new Dictionary
<FieldReference
, int> ();
1080 int? argument
= null;
1082 foreach (Instruction instruction
in constructor
.Body
.Instructions
) {
1083 switch (instruction
.OpCode
.Code
) {
1095 argument
= ((ParameterDefinition
) instruction
.Operand
).Index
+ 1;
1099 FieldReference field
= (FieldReference
) instruction
.Operand
;
1100 if (field
.DeclaringType
.FullName
!= constructor
.DeclaringType
.FullName
)
1103 if (!argument
.HasValue
)
1106 if (!field_mapping
.ContainsKey (field
))
1107 field_mapping
.Add (field
, (int) argument
- 1);
1114 return field_mapping
;
1117 static Dictionary
<PropertyDefinition
, FieldReference
> CreatePropertyFieldMapping (TypeDefinition type
)
1119 Dictionary
<PropertyDefinition
, FieldReference
> property_mapping
= new Dictionary
<PropertyDefinition
, FieldReference
> ();
1121 foreach (PropertyDefinition property
in type
.Properties
) {
1122 if (property
.GetMethod
== null)
1124 if (!property
.GetMethod
.HasBody
)
1127 foreach (Instruction instruction
in property
.GetMethod
.Body
.Instructions
) {
1128 if (instruction
.OpCode
.Code
!= Code
.Ldfld
)
1131 FieldReference field
= (FieldReference
) instruction
.Operand
;
1132 if (field
.DeclaringType
.FullName
!= type
.FullName
)
1135 property_mapping
.Add (property
, field
);
1140 return property_mapping
;
1143 static void PopulateMapping (Dictionary
<string, object> mapping
, MethodDefinition constructor
, CustomAttribute attribute
)
1145 if (!constructor
.HasBody
)
1148 // Custom handling for attributes with arguments which cannot be easily extracted
1149 var ca
= attribute
.ConstructorArguments
;
1150 switch (constructor
.DeclaringType
.FullName
) {
1151 case "System.Runtime.CompilerServices.DecimalConstantAttribute":
1152 var dca
= constructor
.Parameters
[2].ParameterType
== constructor
.Module
.TypeSystem
.Int32
?
1153 new DecimalConstantAttribute ((byte) ca
[0].Value
, (byte) ca
[1].Value
, (int) ca
[2].Value
, (int) ca
[3].Value
, (int) ca
[4].Value
) :
1154 new DecimalConstantAttribute ((byte) ca
[0].Value
, (byte) ca
[1].Value
, (uint) ca
[2].Value
, (uint) ca
[3].Value
, (uint) ca
[4].Value
);
1156 mapping
.Add ("Value", dca
.Value
);
1158 case "System.ComponentModel.BindableAttribute":
1162 if (constructor
.Parameters
[0].ParameterType
== constructor
.Module
.TypeSystem
.Boolean
) {
1163 mapping
.Add ("Bindable", ca
[0].Value
);
1165 throw new NotImplementedException ();
1171 var field_mapping
= CreateArgumentFieldMapping (constructor
);
1172 var property_mapping
= CreatePropertyFieldMapping ((TypeDefinition
) constructor
.DeclaringType
);
1174 foreach (var pair
in property_mapping
) {
1176 if (!field_mapping
.TryGetValue (pair
.Value
, out argument
))
1179 var ca_arg
= ca
[argument
];
1180 if (ca_arg
.Value
is CustomAttributeArgument
)
1181 ca_arg
= (CustomAttributeArgument
) ca_arg
.Value
;
1183 mapping
.Add (pair
.Key
.Name
, GetArgumentValue (ca_arg
.Type
, ca_arg
.Value
));
1187 static object GetArgumentValue (TypeReference reference
, object value)
1189 var type
= reference
.Resolve ();
1194 if (IsFlaggedEnum (type
))
1195 return GetFlaggedEnumValue (type
, value);
1197 return GetEnumValue (type
, value);
1203 static bool IsFlaggedEnum (TypeDefinition type
)
1208 if (!type
.HasCustomAttributes
)
1211 foreach (CustomAttribute attribute
in type
.CustomAttributes
)
1212 if (attribute
.Constructor
.DeclaringType
.FullName
== "System.FlagsAttribute")
1218 static object GetFlaggedEnumValue (TypeDefinition type
, object value)
1221 return GetFlaggedEnumValue (type
, (ulong)value);
1223 long flags
= Convert
.ToInt64 (value);
1224 var signature
= new StringBuilder ();
1226 for (int i
= type
.Fields
.Count
- 1; i
>= 0; i
--) {
1227 FieldDefinition field
= type
.Fields
[i
];
1229 if (!field
.HasConstant
)
1232 long flag
= Convert
.ToInt64 (field
.Constant
);
1237 if ((flags
& flag
) == flag
) {
1238 if (signature
.Length
!= 0)
1239 signature
.Append (", ");
1241 signature
.Append (field
.Name
);
1246 return signature
.ToString ();
1249 static object GetFlaggedEnumValue (TypeDefinition type
, ulong flags
)
1251 var signature
= new StringBuilder ();
1253 for (int i
= type
.Fields
.Count
- 1; i
>= 0; i
--) {
1254 FieldDefinition field
= type
.Fields
[i
];
1256 if (!field
.HasConstant
)
1259 ulong flag
= Convert
.ToUInt64 (field
.Constant
);
1264 if ((flags
& flag
) == flag
) {
1265 if (signature
.Length
!= 0)
1266 signature
.Append (", ");
1268 signature
.Append (field
.Name
);
1273 return signature
.ToString ();
1276 static object GetEnumValue (TypeDefinition type
, object value)
1278 foreach (FieldDefinition field
in type
.Fields
) {
1279 if (!field
.HasConstant
)
1282 if (Comparer
.Default
.Compare (field
.Constant
, value) == 0)
1289 static bool SkipAttribute (CustomAttribute attribute
)
1291 var type_name
= Utils
.CleanupTypeName (attribute
.Constructor
.DeclaringType
);
1293 return !TypeHelper
.IsPublic (attribute
)
1294 || type_name
.EndsWith ("TODOAttribute");
1297 public static void OutputAttributes (XmlDocument doc
, XmlNode parent
, ICustomAttributeProvider provider
)
1299 if (!provider
.HasCustomAttributes
)
1302 AttributeData ad
= new AttributeData (doc
, parent
, provider
.CustomAttributes
);
1307 static class Parameters
{
1309 public static string GetSignature (IList
<ParameterDefinition
> infos
)
1311 if (infos
== null || infos
.Count
== 0)
1312 return string.Empty
;
1314 var signature
= new StringBuilder ();
1315 for (int i
= 0; i
< infos
.Count
; i
++) {
1318 signature
.Append (", ");
1320 ParameterDefinition info
= infos
[i
];
1323 if ((info
.Attributes
& ParameterAttributes
.In
) != 0)
1325 else if ((info
.Attributes
& ParameterAttributes
.Out
) != 0)
1328 modifier
= string.Empty
;
1330 if (modifier
.Length
> 0) {
1331 signature
.Append (modifier
);
1332 signature
.Append (" ");
1335 signature
.Append (Utils
.CleanupTypeName (info
.ParameterType
));
1338 return signature
.ToString ();
1343 class TypeReferenceComparer
: IComparer
1345 public static TypeReferenceComparer Default
= new TypeReferenceComparer ();
1347 public int Compare (object a
, object b
)
1349 TypeReference ta
= (TypeReference
) a
;
1350 TypeReference tb
= (TypeReference
) b
;
1351 int result
= String
.Compare (ta
.Namespace
, tb
.Namespace
);
1355 return String
.Compare (ta
.Name
, tb
.Name
);
1359 class MemberReferenceComparer
: IComparer
1361 public static MemberReferenceComparer Default
= new MemberReferenceComparer ();
1363 public int Compare (object a
, object b
)
1365 MemberReference ma
= (MemberReference
) a
;
1366 MemberReference mb
= (MemberReference
) b
;
1367 return String
.Compare (ma
.Name
, mb
.Name
);
1371 class MethodDefinitionComparer
: IComparer
1373 public static MethodDefinitionComparer Default
= new MethodDefinitionComparer ();
1375 public int Compare (object a
, object b
)
1377 MethodDefinition ma
= (MethodDefinition
) a
;
1378 MethodDefinition mb
= (MethodDefinition
) b
;
1379 int res
= String
.Compare (ma
.Name
, mb
.Name
);
1383 if (!ma
.HasParameters
&& !mb
.HasParameters
)
1386 if (!ma
.HasParameters
)
1389 if (!mb
.HasParameters
)
1392 IList
<ParameterDefinition
> pia
= ma
.Parameters
;
1393 IList
<ParameterDefinition
> pib
= mb
.Parameters
;
1394 res
= pia
.Count
- pib
.Count
;
1398 string siga
= Parameters
.GetSignature (pia
);
1399 string sigb
= Parameters
.GetSignature (pib
);
1400 return String
.Compare (siga
, sigb
);