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
;
14 using System
.Runtime
.InteropServices
;
15 using System
.Security
.Permissions
;
26 public static int Main (string [] args
)
31 AssemblyCollection acoll
= new AssemblyCollection ();
33 foreach (string fullName
in args
) {
37 XmlDocument doc
= new XmlDocument ();
41 var writer
= new WellFormedXmlWriter (new XmlTextWriter (Console
.Out
) { Formatting = Formatting.Indented }
);
42 XmlNode decl
= doc
.CreateXmlDeclaration ("1.0", "utf-8", null);
43 doc
.InsertBefore (decl
, doc
.DocumentElement
);
51 public static string CleanupTypeName (TypeReference type
)
53 return CleanupTypeName (type
.FullName
);
56 static string CleanupTypeName (string t
)
58 return t
.Replace ('<', '[').Replace ('>', ']').Replace ('/', '+');
62 class AssemblyCollection
65 List
<AssemblyDefinition
> assemblies
= new List
<AssemblyDefinition
> ();
67 public AssemblyCollection ()
71 public bool Add (string name
)
73 AssemblyDefinition ass
= LoadAssembly (name
);
81 public void DoOutput ()
84 throw new InvalidOperationException ("Document not set");
86 XmlNode nassemblies
= document
.CreateElement ("assemblies", null);
87 document
.AppendChild (nassemblies
);
88 foreach (AssemblyDefinition a
in assemblies
) {
89 AssemblyData data
= new AssemblyData (document
, nassemblies
, a
);
94 public XmlDocument Document
{
95 set { document = value; }
98 AssemblyDefinition
LoadAssembly (string assembly
)
101 return TypeHelper
.Resolver
.Resolve (assembly
);
108 abstract class BaseData
110 protected XmlDocument document
;
111 protected XmlNode parent
;
113 protected BaseData (XmlDocument doc
, XmlNode parent
)
116 this.parent
= parent
;
119 public abstract void DoOutput ();
121 protected void AddAttribute (XmlNode node
, string name
, string value)
123 XmlAttribute attr
= document
.CreateAttribute (name
);
125 node
.Attributes
.Append (attr
);
129 class AssemblyData
: BaseData
131 AssemblyDefinition ass
;
133 public AssemblyData (XmlDocument document
, XmlNode parent
, AssemblyDefinition ass
)
134 : base (document
, parent
)
139 public override void DoOutput ()
141 if (document
== null)
142 throw new InvalidOperationException ("Document not set");
144 XmlNode nassembly
= document
.CreateElement ("assembly", null);
145 AssemblyNameDefinition aname
= ass
.Name
;
146 AddAttribute (nassembly
, "name", aname
.Name
);
147 AddAttribute (nassembly
, "version", aname
.Version
.ToString ());
148 parent
.AppendChild (nassembly
);
149 AttributeData
.OutputAttributes (document
, nassembly
, ass
.CustomAttributes
);
150 TypeDefinitionCollection typesCollection
= ass
.MainModule
.Types
;
151 if (typesCollection
== null || typesCollection
.Count
== 0)
153 object [] typesArray
= new object [typesCollection
.Count
];
154 for (int i
= 0; i
< typesCollection
.Count
; i
++) {
155 typesArray
[i
] = typesCollection
[i
];
157 Array
.Sort (typesArray
, TypeReferenceComparer
.Default
);
159 XmlNode nss
= document
.CreateElement ("namespaces", null);
160 nassembly
.AppendChild (nss
);
162 string current_namespace
= "$%&$&";
164 XmlNode classes
= null;
165 foreach (TypeDefinition t
in typesArray
) {
166 if (string.IsNullOrEmpty (t
.Namespace
))
169 if ((t
.Attributes
& TypeAttributes
.VisibilityMask
) != TypeAttributes
.Public
)
172 if (t
.DeclaringType
!= null)
173 continue; // enforce !nested
175 if (t
.Namespace
!= current_namespace
) {
176 current_namespace
= t
.Namespace
;
177 ns
= document
.CreateElement ("namespace", null);
178 AddAttribute (ns
, "name", current_namespace
);
179 nss
.AppendChild (ns
);
180 classes
= document
.CreateElement ("classes", null);
181 ns
.AppendChild (classes
);
184 TypeData bd
= new TypeData (document
, classes
, t
);
190 abstract class MemberData
: BaseData
192 MemberReference
[] members
;
194 public MemberData (XmlDocument document
, XmlNode parent
, MemberReference
[] members
)
195 : base (document
, parent
)
197 this.members
= members
;
200 public override void DoOutput ()
202 XmlNode mclass
= document
.CreateElement (ParentTag
, null);
203 parent
.AppendChild (mclass
);
205 foreach (MemberReference member
in members
) {
206 XmlNode mnode
= document
.CreateElement (Tag
, null);
207 mclass
.AppendChild (mnode
);
208 AddAttribute (mnode
, "name", GetName (member
));
209 if (!NoMemberAttributes
)
210 AddAttribute (mnode
, "attrib", GetMemberAttributes (member
));
212 AttributeData
.OutputAttributes (document
, mnode
, GetCustomAttributes (member
));
214 AddExtraData (mnode
, member
);
219 protected abstract CustomAttributeCollection
GetCustomAttributes (MemberReference member
);
221 protected virtual void AddExtraData (XmlNode p
, MemberReference memberDefenition
)
225 protected virtual string GetName (MemberReference memberDefenition
)
230 protected virtual string GetMemberAttributes (MemberReference memberDefenition
)
235 public virtual bool NoMemberAttributes
{
236 get { return false; }
240 public virtual string ParentTag
{
241 get { return "NoPARENTTAG"; }
244 public virtual string Tag
{
245 get { return "NoTAG"; }
248 public static void OutputGenericParameters (XmlDocument document
, XmlNode nclass
, IGenericParameterProvider provider
)
250 if (provider
.GenericParameters
.Count
== 0)
253 var gparameters
= provider
.GenericParameters
;
255 XmlElement ngeneric
= document
.CreateElement (string.Format ("generic-parameters"));
256 nclass
.AppendChild (ngeneric
);
258 foreach (GenericParameter gp
in gparameters
) {
259 XmlElement nparam
= document
.CreateElement (string.Format ("generic-parameter"));
260 nparam
.SetAttribute ("name", gp
.Name
);
261 nparam
.SetAttribute ("attributes", ((int) gp
.Attributes
).ToString ());
263 AttributeData
.OutputAttributes (document
, nparam
, gp
.CustomAttributes
);
265 ngeneric
.AppendChild (nparam
);
267 var constraints
= gp
.Constraints
;
268 if (constraints
.Count
== 0)
271 XmlElement nconstraint
= document
.CreateElement ("generic-parameter-constraints");
273 foreach (TypeReference constraint
in constraints
) {
274 XmlElement ncons
= document
.CreateElement ("generic-parameter-constraint");
275 ncons
.SetAttribute ("name", Utils
.CleanupTypeName (constraint
));
276 nconstraint
.AppendChild (ncons
);
279 nparam
.AppendChild (nconstraint
);
284 class TypeData
: MemberData
288 public TypeData (XmlDocument document
, XmlNode parent
, TypeDefinition type
)
289 : base (document
, parent
, null)
294 protected override CustomAttributeCollection
GetCustomAttributes (MemberReference member
) {
295 return ((TypeDefinition
) member
).CustomAttributes
;
298 public override void DoOutput ()
300 if (document
== null)
301 throw new InvalidOperationException ("Document not set");
303 XmlNode nclass
= document
.CreateElement ("class", null);
304 AddAttribute (nclass
, "name", type
.Name
);
305 string classType
= GetClassType (type
);
306 AddAttribute (nclass
, "type", classType
);
308 if (type
.BaseType
!= null)
309 AddAttribute (nclass
, "base", Utils
.CleanupTypeName (type
.BaseType
));
312 AddAttribute (nclass
, "sealed", "true");
315 AddAttribute (nclass
, "abstract", "true");
317 if ( (type
.Attributes
& TypeAttributes
.Serializable
) != 0 || type
.IsEnum
)
318 AddAttribute (nclass
, "serializable", "true");
320 string charSet
= GetCharSet (type
);
321 AddAttribute (nclass
, "charset", charSet
);
323 string layout
= GetLayout (type
);
325 AddAttribute (nclass
, "layout", layout
);
327 parent
.AppendChild (nclass
);
329 AttributeData
.OutputAttributes (document
, nclass
, GetCustomAttributes(type
));
331 XmlNode ifaces
= null;
333 foreach (TypeReference iface
in TypeHelper
.GetInterfaces (type
)) {
334 if (!TypeHelper
.IsPublic (iface
))
335 // we're only interested in public interfaces
338 if (ifaces
== null) {
339 ifaces
= document
.CreateElement ("interfaces", null);
340 nclass
.AppendChild (ifaces
);
343 XmlNode iface_node
= document
.CreateElement ("interface", null);
344 AddAttribute (iface_node
, "name", Utils
.CleanupTypeName (iface
));
345 ifaces
.AppendChild (iface_node
);
348 MemberData
.OutputGenericParameters (document
, nclass
, type
);
350 ArrayList members
= new ArrayList ();
352 FieldDefinition
[] fields
= GetFields (type
);
353 if (fields
.Length
> 0) {
354 Array
.Sort (fields
, MemberReferenceComparer
.Default
);
355 FieldData fd
= new FieldData (document
, nclass
, fields
);
360 var value_type
= GetEnumValueField (type
);
361 if (value_type
== null)
362 throw new NotSupportedException ();
364 AddAttribute (nclass
, "enumtype", Utils
.CleanupTypeName (value_type
.FieldType
));
367 MethodDefinition
[] ctors
= GetConstructors (type
);
368 if (ctors
.Length
> 0) {
369 Array
.Sort (ctors
, MemberReferenceComparer
.Default
);
370 members
.Add (new ConstructorData (document
, nclass
, ctors
));
373 PropertyDefinition
[] properties
= GetProperties (type
);
374 if (properties
.Length
> 0) {
375 Array
.Sort (properties
, MemberReferenceComparer
.Default
);
376 members
.Add (new PropertyData (document
, nclass
, properties
));
379 EventDefinition
[] events
= GetEvents (type
);
380 if (events
.Length
> 0) {
381 Array
.Sort (events
, MemberReferenceComparer
.Default
);
382 members
.Add (new EventData (document
, nclass
, events
));
385 MethodDefinition
[] methods
= GetMethods (type
);
386 if (methods
.Length
> 0) {
387 Array
.Sort (methods
, MemberReferenceComparer
.Default
);
388 members
.Add (new MethodData (document
, nclass
, methods
));
391 foreach (MemberData md
in members
)
394 NestedTypeCollection nested
= type
.NestedTypes
;
395 //remove non public(familiy) and nested in second degree
396 for (int i
= nested
.Count
- 1; i
>= 0; i
--) {
397 TypeDefinition t
= nested
[i
];
398 if ((t
.Attributes
& TypeAttributes
.VisibilityMask
) == TypeAttributes
.NestedPublic
||
399 (t
.Attributes
& TypeAttributes
.VisibilityMask
) == TypeAttributes
.NestedFamily
||
400 (t
.Attributes
& TypeAttributes
.VisibilityMask
) == TypeAttributes
.NestedFamORAssem
) {
402 if (t
.DeclaringType
== type
)
403 continue; // not nested of nested
410 if (nested
.Count
> 0) {
411 XmlNode classes
= document
.CreateElement ("classes", null);
412 nclass
.AppendChild (classes
);
413 foreach (TypeDefinition t
in nested
) {
414 TypeData td
= new TypeData (document
, classes
, t
);
420 static FieldReference
GetEnumValueField (TypeDefinition type
)
422 foreach (FieldDefinition field
in type
.Fields
)
423 if (field
.IsSpecialName
&& field
.Name
== "value__")
429 protected override string GetMemberAttributes (MemberReference member
)
432 throw new InvalidOperationException ("odd");
434 return ((int) type
.Attributes
).ToString (CultureInfo
.InvariantCulture
);
437 public static bool MustDocumentMethod (MethodDefinition method
) {
439 MethodAttributes maskedAccess
= method
.Attributes
& MethodAttributes
.MemberAccessMask
;
440 return maskedAccess
== MethodAttributes
.Public
441 || maskedAccess
== MethodAttributes
.Family
442 || maskedAccess
== MethodAttributes
.FamORAssem
;
445 static string GetClassType (TypeDefinition t
)
456 if (TypeHelper
.IsDelegate(t
))
462 static string GetCharSet (TypeDefinition type
)
464 TypeAttributes maskedStringFormat
= type
.Attributes
& TypeAttributes
.StringFormatMask
;
465 if (maskedStringFormat
== TypeAttributes
.AnsiClass
)
466 return CharSet
.Ansi
.ToString ();
468 if (maskedStringFormat
== TypeAttributes
.AutoClass
)
469 return CharSet
.Auto
.ToString ();
471 if (maskedStringFormat
== TypeAttributes
.UnicodeClass
)
472 return CharSet
.Unicode
.ToString ();
474 return CharSet
.None
.ToString ();
477 static string GetLayout (TypeDefinition type
)
479 TypeAttributes maskedLayout
= type
.Attributes
& TypeAttributes
.LayoutMask
;
480 if (maskedLayout
== TypeAttributes
.AutoLayout
)
481 return LayoutKind
.Auto
.ToString ();
483 if (maskedLayout
== TypeAttributes
.ExplicitLayout
)
484 return LayoutKind
.Explicit
.ToString ();
486 if (maskedLayout
== TypeAttributes
.SequentialLayout
)
487 return LayoutKind
.Sequential
.ToString ();
492 FieldDefinition
[] GetFields (TypeDefinition type
) {
493 ArrayList list
= new ArrayList ();
495 FieldDefinitionCollection fields
= type
.Fields
;
496 foreach (FieldDefinition field
in fields
) {
497 if (field
.IsSpecialName
)
500 // we're only interested in public or protected members
501 FieldAttributes maskedVisibility
= (field
.Attributes
& FieldAttributes
.FieldAccessMask
);
502 if (maskedVisibility
== FieldAttributes
.Public
503 || maskedVisibility
== FieldAttributes
.Family
504 || maskedVisibility
== FieldAttributes
.FamORAssem
) {
509 return (FieldDefinition
[]) list
.ToArray (typeof (FieldDefinition
));
513 internal static PropertyDefinition
[] GetProperties (TypeDefinition type
) {
514 ArrayList list
= new ArrayList ();
516 PropertyDefinitionCollection properties
= type
.Properties
;//type.GetProperties (flags);
517 foreach (PropertyDefinition property
in properties
) {
518 MethodDefinition getMethod
= property
.GetMethod
;
519 MethodDefinition setMethod
= property
.SetMethod
;
521 bool hasGetter
= (getMethod
!= null) && MustDocumentMethod (getMethod
);
522 bool hasSetter
= (setMethod
!= null) && MustDocumentMethod (setMethod
);
524 // if neither the getter or setter should be documented, then
526 if (hasGetter
|| hasSetter
) {
531 return (PropertyDefinition
[]) list
.ToArray (typeof (PropertyDefinition
));
534 private MethodDefinition
[] GetMethods (TypeDefinition type
)
536 ArrayList list
= new ArrayList ();
538 MethodDefinitionCollection methods
= type
.Methods
;//type.GetMethods (flags);
539 foreach (MethodDefinition method
in methods
) {
540 if (method
.IsSpecialName
&& !method
.Name
.StartsWith ("op_"))
543 // we're only interested in public or protected members
544 if (!MustDocumentMethod(method
))
547 if (IsFinalizer (method
))
553 return (MethodDefinition
[]) list
.ToArray (typeof (MethodDefinition
));
556 static bool IsFinalizer (MethodDefinition method
)
558 if (method
.Name
!= "Finalize")
561 if (!method
.IsVirtual
)
564 if (method
.Parameters
.Count
!= 0)
570 private MethodDefinition
[] GetConstructors (TypeDefinition type
)
572 ArrayList list
= new ArrayList ();
574 ConstructorCollection ctors
= type
.Constructors
;//type.GetConstructors (flags);
575 foreach (MethodDefinition constructor
in ctors
) {
576 // we're only interested in public or protected members
577 if (!MustDocumentMethod(constructor
))
580 list
.Add (constructor
);
583 return (MethodDefinition
[]) list
.ToArray (typeof (MethodDefinition
));
586 private EventDefinition
[] GetEvents (TypeDefinition type
)
588 ArrayList list
= new ArrayList ();
590 EventDefinitionCollection events
= type
.Events
;//type.GetEvents (flags);
591 foreach (EventDefinition eventDef
in events
) {
592 MethodDefinition addMethod
= eventDef
.AddMethod
;//eventInfo.GetAddMethod (true);
594 if (addMethod
== null || !MustDocumentMethod (addMethod
))
600 return (EventDefinition
[]) list
.ToArray (typeof (EventDefinition
));
604 class FieldData
: MemberData
606 public FieldData (XmlDocument document
, XmlNode parent
, FieldDefinition
[] members
)
607 : base (document
, parent
, members
)
611 protected override CustomAttributeCollection
GetCustomAttributes (MemberReference member
) {
612 return ((FieldDefinition
) member
).CustomAttributes
;
615 protected override string GetName (MemberReference memberDefenition
)
617 FieldDefinition field
= (FieldDefinition
) memberDefenition
;
621 protected override string GetMemberAttributes (MemberReference memberDefenition
)
623 FieldDefinition field
= (FieldDefinition
) memberDefenition
;
624 return ((int) field
.Attributes
).ToString (CultureInfo
.InvariantCulture
);
627 protected override void AddExtraData (XmlNode p
, MemberReference memberDefenition
)
629 base.AddExtraData (p
, memberDefenition
);
630 FieldDefinition field
= (FieldDefinition
) memberDefenition
;
631 AddAttribute (p
, "fieldtype", Utils
.CleanupTypeName (field
.FieldType
));
633 if (field
.IsLiteral
) {
634 object value = field
.Constant
;//object value = field.GetValue (null);
635 string stringValue
= null;
636 //if (value is Enum) {
637 // // FIXME: when Mono bug #60090 has been
638 // // fixed, we should just be able to use
639 // // Convert.ToString
640 // stringValue = ((Enum) value).ToString ("D", CultureInfo.InvariantCulture);
643 stringValue
= Convert
.ToString (value, CultureInfo
.InvariantCulture
);
646 if (stringValue
!= null)
647 AddAttribute (p
, "value", stringValue
);
651 public override string ParentTag
{
652 get { return "fields"; }
655 public override string Tag
{
656 get { return "field"; }
660 class PropertyData
: MemberData
662 public PropertyData (XmlDocument document
, XmlNode parent
, PropertyDefinition
[] members
)
663 : base (document
, parent
, members
)
667 protected override CustomAttributeCollection
GetCustomAttributes (MemberReference member
) {
668 return ((PropertyDefinition
) member
).CustomAttributes
;
671 protected override string GetName (MemberReference memberDefenition
)
673 PropertyDefinition prop
= (PropertyDefinition
) memberDefenition
;
677 protected override void AddExtraData (XmlNode p
, MemberReference memberDefenition
)
679 base.AddExtraData (p
, memberDefenition
);
680 PropertyDefinition prop
= (PropertyDefinition
) memberDefenition
;
681 AddAttribute (p
, "ptype", Utils
.CleanupTypeName (prop
.PropertyType
));
682 MethodDefinition _get
= prop
.GetMethod
;
683 MethodDefinition _set
= prop
.SetMethod
;
684 bool haveGet
= (_get
!= null && TypeData
.MustDocumentMethod(_get
));
685 bool haveSet
= (_set
!= null && TypeData
.MustDocumentMethod(_set
));
686 MethodDefinition
[] methods
;
688 if (haveGet
&& haveSet
) {
689 methods
= new MethodDefinition
[] { _get, _set }
;
690 } else if (haveGet
) {
691 methods
= new MethodDefinition
[] { _get }
;
692 } else if (haveSet
) {
693 methods
= new MethodDefinition
[] { _set }
;
699 string parms
= Parameters
.GetSignature (methods
[0].Parameters
);
700 if (!string.IsNullOrEmpty (parms
))
701 AddAttribute (p
, "params", parms
);
703 MethodData data
= new MethodData (document
, p
, methods
);
704 //data.NoMemberAttributes = true;
708 protected override string GetMemberAttributes (MemberReference memberDefenition
)
710 PropertyDefinition prop
= (PropertyDefinition
) memberDefenition
;
711 return ((int) prop
.Attributes
).ToString (CultureInfo
.InvariantCulture
);
714 public override string ParentTag
{
715 get { return "properties"; }
718 public override string Tag
{
719 get { return "property"; }
723 class EventData
: MemberData
725 public EventData (XmlDocument document
, XmlNode parent
, EventDefinition
[] members
)
726 : base (document
, parent
, members
)
730 protected override CustomAttributeCollection
GetCustomAttributes (MemberReference member
) {
731 return ((EventDefinition
) member
).CustomAttributes
;
734 protected override string GetName (MemberReference memberDefenition
)
736 EventDefinition evt
= (EventDefinition
) memberDefenition
;
740 protected override string GetMemberAttributes (MemberReference memberDefenition
)
742 EventDefinition evt
= (EventDefinition
) memberDefenition
;
743 return ((int) evt
.Attributes
).ToString (CultureInfo
.InvariantCulture
);
746 protected override void AddExtraData (XmlNode p
, MemberReference memberDefenition
)
748 base.AddExtraData (p
, memberDefenition
);
749 EventDefinition evt
= (EventDefinition
) memberDefenition
;
750 AddAttribute (p
, "eventtype", Utils
.CleanupTypeName (evt
.EventType
));
753 public override string ParentTag
{
754 get { return "events"; }
757 public override string Tag
{
758 get { return "event"; }
762 class MethodData
: MemberData
766 public MethodData (XmlDocument document
, XmlNode parent
, MethodDefinition
[] members
)
767 : base (document
, parent
, members
)
771 protected override CustomAttributeCollection
GetCustomAttributes (MemberReference member
) {
772 return ((MethodDefinition
) member
).CustomAttributes
;
775 protected override string GetName (MemberReference memberDefenition
)
777 MethodDefinition method
= (MethodDefinition
) memberDefenition
;
778 string name
= method
.Name
;
779 string parms
= Parameters
.GetSignature (method
.Parameters
);
781 return string.Format ("{0}({1})", name
, parms
);
784 protected override string GetMemberAttributes (MemberReference memberDefenition
)
786 MethodDefinition method
= (MethodDefinition
) memberDefenition
;
787 return ((int)( method
.Attributes
)).ToString (CultureInfo
.InvariantCulture
);
790 protected override void AddExtraData (XmlNode p
, MemberReference memberDefenition
)
792 base.AddExtraData (p
, memberDefenition
);
794 if (!(memberDefenition
is MethodDefinition
))
797 MethodDefinition mbase
= (MethodDefinition
) memberDefenition
;
799 ParameterData parms
= new ParameterData (document
, p
, mbase
.Parameters
);
802 if (mbase
.IsAbstract
)
803 AddAttribute (p
, "abstract", "true");
805 AddAttribute (p
, "virtual", "true");
807 AddAttribute (p
, "static", "true");
809 string rettype
= Utils
.CleanupTypeName (mbase
.ReturnType
.ReturnType
);
810 if (rettype
!= "System.Void" || !mbase
.IsConstructor
)
811 AddAttribute (p
, "returntype", (rettype
));
813 AttributeData
.OutputAttributes (document
, p
, mbase
.ReturnType
.CustomAttributes
);
815 MemberData
.OutputGenericParameters (document
, p
, mbase
);
818 public override bool NoMemberAttributes
{
819 get { return noAtts; }
820 set { noAtts = value; }
823 public override string ParentTag
{
824 get { return "methods"; }
827 public override string Tag
{
828 get { return "method"; }
832 class ConstructorData
: MethodData
834 public ConstructorData (XmlDocument document
, XmlNode parent
, MethodDefinition
[] members
)
835 : base (document
, parent
, members
)
839 public override string ParentTag
{
840 get { return "constructors"; }
843 public override string Tag
{
844 get { return "constructor"; }
848 class ParameterData
: BaseData
850 private ParameterDefinitionCollection parameters
;
852 public ParameterData (XmlDocument document
, XmlNode parent
, ParameterDefinitionCollection parameters
)
853 : base (document
, parent
)
855 this.parameters
= parameters
;
858 public override void DoOutput ()
860 XmlNode parametersNode
= document
.CreateElement ("parameters");
861 parent
.AppendChild (parametersNode
);
863 foreach (ParameterDefinition parameter
in parameters
) {
864 XmlNode paramNode
= document
.CreateElement ("parameter");
865 parametersNode
.AppendChild (paramNode
);
866 AddAttribute (paramNode
, "name", parameter
.Name
);
867 AddAttribute (paramNode
, "position", parameter
.Method
.Parameters
.IndexOf(parameter
).ToString(CultureInfo
.InvariantCulture
));
868 AddAttribute (paramNode
, "attrib", ((int) parameter
.Attributes
).ToString());
870 string direction
= "in";
872 if (parameter
.ParameterType
is ReferenceType
)
873 direction
= parameter
.IsOut
? "out" : "ref";
875 TypeReference t
= parameter
.ParameterType
;
876 AddAttribute (paramNode
, "type", Utils
.CleanupTypeName (t
));
878 if (parameter
.IsOptional
) {
879 AddAttribute (paramNode
, "optional", "true");
880 if (parameter
.HasConstant
)
881 AddAttribute (paramNode
, "defaultValue", parameter
.Constant
== null ? "NULL" : parameter
.Constant
.ToString ());
884 if (direction
!= "in")
885 AddAttribute (paramNode
, "direction", direction
);
887 AttributeData
.OutputAttributes (document
, paramNode
, parameter
.CustomAttributes
);
892 class AttributeData
: BaseData
894 CustomAttributeCollection atts
;
896 AttributeData (XmlDocument doc
, XmlNode parent
, CustomAttributeCollection attributes
)
902 public override void DoOutput ()
904 if (document
== null)
905 throw new InvalidOperationException ("Document not set");
907 if (atts
== null || atts
.Count
== 0)
910 XmlNode natts
= parent
.SelectSingleNode("attributes");
912 natts
= document
.CreateElement ("attributes", null);
913 parent
.AppendChild (natts
);
916 for (int i
= 0; i
< atts
.Count
; ++i
) {
917 CustomAttribute att
= atts
[i
];
925 string attName
= Utils
.CleanupTypeName (att
.Constructor
.DeclaringType
);
926 if (SkipAttribute (att
))
929 XmlNode node
= document
.CreateElement ("attribute");
930 AddAttribute (node
, "name", attName
);
932 XmlNode properties
= null;
934 Dictionary
<string, object> attribute_mapping
= CreateAttributeMapping (att
);
936 foreach (string name
in attribute_mapping
.Keys
) {
937 if (name
== "TypeId")
940 if (properties
== null) {
941 properties
= node
.AppendChild (document
.CreateElement ("properties"));
944 object o
= attribute_mapping
[name
];
946 XmlNode n
= properties
.AppendChild (document
.CreateElement ("property"));
947 AddAttribute (n
, "name", name
);
950 AddAttribute (n
, "value", "null");
953 string value = o
.ToString ();
954 if (attName
.EndsWith ("GuidAttribute"))
955 value = value.ToUpper ();
956 AddAttribute (n
, "value", value);
959 natts
.AppendChild (node
);
963 static Dictionary
<string, object> CreateAttributeMapping (CustomAttribute attribute
)
965 var mapping
= new Dictionary
<string, object> ();
967 PopulateMapping (mapping
, attribute
);
969 var constructor
= attribute
.Constructor
.Resolve ();
970 if (constructor
== null || constructor
.Parameters
.Count
== 0)
973 PopulateMapping (mapping
, constructor
, attribute
);
978 static void PopulateMapping (Dictionary
<string, object> mapping
, CustomAttribute attribute
)
980 foreach (DictionaryEntry entry
in attribute
.Properties
) {
981 var name
= (string) entry
.Key
;
983 mapping
.Add (name
, GetArgumentValue (attribute
.GetPropertyType (name
), entry
.Value
));
987 static Dictionary
<FieldReference
, int> CreateArgumentFieldMapping (MethodDefinition constructor
)
989 Dictionary
<FieldReference
, int> field_mapping
= new Dictionary
<FieldReference
, int> ();
991 int? argument
= null;
993 foreach (Instruction instruction
in constructor
.Body
.Instructions
) {
994 switch (instruction
.OpCode
.Code
) {
1006 argument
= ((ParameterDefinition
) instruction
.Operand
).Sequence
;
1010 FieldReference field
= (FieldReference
) instruction
.Operand
;
1011 if (field
.DeclaringType
.FullName
!= constructor
.DeclaringType
.FullName
)
1014 if (!argument
.HasValue
)
1017 if (!field_mapping
.ContainsKey (field
))
1018 field_mapping
.Add (field
, (int) argument
- 1);
1025 return field_mapping
;
1028 static Dictionary
<PropertyDefinition
, FieldReference
> CreatePropertyFieldMapping (TypeDefinition type
)
1030 Dictionary
<PropertyDefinition
, FieldReference
> property_mapping
= new Dictionary
<PropertyDefinition
, FieldReference
> ();
1032 foreach (PropertyDefinition property
in type
.Properties
) {
1033 if (property
.GetMethod
== null)
1035 if (!property
.GetMethod
.HasBody
)
1038 foreach (Instruction instruction
in property
.GetMethod
.Body
.Instructions
) {
1039 if (instruction
.OpCode
.Code
!= Code
.Ldfld
)
1042 FieldReference field
= (FieldReference
) instruction
.Operand
;
1043 if (field
.DeclaringType
.FullName
!= type
.FullName
)
1046 property_mapping
.Add (property
, field
);
1051 return property_mapping
;
1054 static void PopulateMapping (Dictionary
<string, object> mapping
, MethodDefinition constructor
, CustomAttribute attribute
)
1056 if (!constructor
.HasBody
)
1059 var field_mapping
= CreateArgumentFieldMapping (constructor
);
1060 var property_mapping
= CreatePropertyFieldMapping ((TypeDefinition
) constructor
.DeclaringType
);
1062 foreach (var pair
in property_mapping
) {
1064 if (!field_mapping
.TryGetValue (pair
.Value
, out argument
))
1067 mapping
.Add (pair
.Key
.Name
, GetArgumentValue (constructor
.Parameters
[argument
].ParameterType
, attribute
.ConstructorParameters
[argument
]));
1071 static object GetArgumentValue (TypeReference reference
, object value)
1073 var type
= reference
.Resolve ();
1078 if (IsFlaggedEnum (type
))
1079 return GetFlaggedEnumValue (type
, value);
1081 return GetEnumValue (type
, value);
1087 static bool IsFlaggedEnum (TypeDefinition type
)
1092 if (type
.CustomAttributes
.Count
== 0)
1095 foreach (CustomAttribute attribute
in type
.CustomAttributes
)
1096 if (attribute
.Constructor
.DeclaringType
.FullName
== "System.FlagsAttribute")
1102 static object GetFlaggedEnumValue (TypeDefinition type
, object value)
1104 long flags
= Convert
.ToInt64 (value);
1105 var signature
= new StringBuilder ();
1107 for (int i
= type
.Fields
.Count
- 1; i
>= 0; i
--) {
1108 FieldDefinition field
= type
.Fields
[i
];
1110 if (!field
.HasConstant
)
1113 long flag
= Convert
.ToInt64 (field
.Constant
);
1118 if ((flags
& flag
) == flag
) {
1119 if (signature
.Length
!= 0)
1120 signature
.Append (", ");
1122 signature
.Append (field
.Name
);
1127 return signature
.ToString ();
1130 static object GetEnumValue (TypeDefinition type
, object value)
1132 foreach (FieldDefinition field
in type
.Fields
) {
1133 if (!field
.HasConstant
)
1136 if (Comparer
.Default
.Compare (field
.Constant
, value) == 0)
1143 static bool SkipAttribute (CustomAttribute attribute
)
1145 var type_name
= Utils
.CleanupTypeName (attribute
.Constructor
.DeclaringType
);
1147 return !TypeHelper
.IsPublic (attribute
)
1148 || type_name
.EndsWith ("TODOAttribute");
1151 public static void OutputAttributes (XmlDocument doc
, XmlNode parent
, CustomAttributeCollection attributes
)
1153 AttributeData ad
= new AttributeData (doc
, parent
, attributes
);
1158 static class Parameters
{
1160 public static string GetSignature (ParameterDefinitionCollection infos
)
1162 if (infos
== null || infos
.Count
== 0)
1165 var signature
= new StringBuilder ();
1166 for (int i
= 0; i
< infos
.Count
; i
++) {
1169 signature
.Append (", ");
1171 ParameterDefinition info
= infos
[i
];
1174 if ((info
.Attributes
& ParameterAttributes
.In
) != 0)
1176 else if ((info
.Attributes
& ParameterAttributes
.Retval
) != 0)
1178 else if ((info
.Attributes
& ParameterAttributes
.Out
) != 0)
1181 modifier
= string.Empty
;
1183 if (modifier
.Length
> 0)
1184 signature
.AppendFormat ("{0} ", modifier
);
1186 signature
.Append (Utils
.CleanupTypeName (info
.ParameterType
));
1189 return signature
.ToString ();
1194 class TypeReferenceComparer
: IComparer
1196 public static TypeReferenceComparer Default
= new TypeReferenceComparer ();
1198 public int Compare (object a
, object b
)
1200 TypeReference ta
= (TypeReference
) a
;
1201 TypeReference tb
= (TypeReference
) b
;
1202 int result
= String
.Compare (ta
.Namespace
, tb
.Namespace
);
1206 return String
.Compare (ta
.Name
, tb
.Name
);
1210 class MemberReferenceComparer
: IComparer
1212 public static MemberReferenceComparer Default
= new MemberReferenceComparer ();
1214 public int Compare (object a
, object b
)
1216 MemberReference ma
= (MemberReference
) a
;
1217 MemberReference mb
= (MemberReference
) b
;
1218 return String
.Compare (ma
.Name
, mb
.Name
);
1222 class MethodDefinitionComparer
: IComparer
1224 public static MethodDefinitionComparer Default
= new MethodDefinitionComparer ();
1226 public int Compare (object a
, object b
)
1228 MethodDefinition ma
= (MethodDefinition
) a
;
1229 MethodDefinition mb
= (MethodDefinition
) b
;
1230 int res
= String
.Compare (ma
.Name
, mb
.Name
);
1234 ParameterDefinitionCollection pia
= ma
.Parameters
;
1235 ParameterDefinitionCollection pib
= mb
.Parameters
;
1236 res
= pia
.Count
- pib
.Count
;
1240 string siga
= Parameters
.GetSignature (pia
);
1241 string sigb
= Parameters
.GetSignature (pib
);
1242 return String
.Compare (siga
, sigb
);