merge r98600
[mono.git] / mcs / tools / corcompare / mono-api-info.cs
1 //
2 // mono-api-info.cs - Dumps public assembly information to an xml file.
3 //
4 // Authors:
5 //      Gonzalo Paniagua Javier (gonzalo@ximian.com)
6 //
7 // Copyright (C) 2003-2005 Novell, Inc (http://www.novell.com)
8 //
9
10 using System;
11 using System.Collections;
12 using System.Globalization;
13 using System.Reflection;
14 using System.Runtime.InteropServices;
15 using System.Security.Permissions;
16 using System.Text;
17 using System.Xml;
18
19 namespace Mono.AssemblyInfo
20 {
21         class Driver
22         {
23                 static int Main (string [] args)
24                 {
25                         if (args.Length == 0)
26                                 return 1;
27
28                         AssemblyCollection acoll = new AssemblyCollection ();
29                         
30                         foreach (string fullName in args) {
31                                 acoll.Add (fullName);
32                         }
33
34                         XmlDocument doc = new XmlDocument ();
35                         acoll.Document = doc;
36                         acoll.DoOutput ();
37
38                         XmlTextWriter writer = new XmlTextWriter (Console.Out);
39                         writer.Formatting = Formatting.Indented;
40                         XmlNode decl = doc.CreateXmlDeclaration ("1.0", null, null);
41                         doc.InsertBefore (decl, doc.DocumentElement);
42                         doc.WriteTo (writer);
43                         return 0;
44                 }
45         }
46
47         class AssemblyCollection
48         {
49                 XmlDocument document;
50                 ArrayList assemblies;
51
52                 public AssemblyCollection ()
53                 {
54                         assemblies = new ArrayList ();
55                 }
56
57                 public bool Add (string name)
58                 {
59                         Assembly ass = LoadAssembly (name);
60                         if (ass == null)
61                                 return false;
62
63                         assemblies.Add (ass);
64                         return true;
65                 }
66
67                 public void DoOutput ()
68                 {
69                         if (document == null)
70                                 throw new InvalidOperationException ("Document not set");
71
72                         XmlNode nassemblies = document.CreateElement ("assemblies", null);
73                         document.AppendChild (nassemblies);
74                         foreach (Assembly a in assemblies) {
75                                 AssemblyData data = new AssemblyData (document, nassemblies, a);
76                                 data.DoOutput ();
77                         }
78                 }
79
80                 public XmlDocument Document {
81                         set { document = value; }
82                 }
83                 
84                 static Assembly LoadAssembly (string aname)
85                 {
86                         Assembly ass = null;
87                         try {
88                                 string name = aname;
89                                 if (!name.EndsWith (".dll"))
90                                         name += ".dll";
91                                 ass = Assembly.LoadFrom (name);
92                                 return ass;
93                         } catch { }
94
95                         try {
96                                 ass = Assembly.LoadWithPartialName (aname);
97                                 return ass;
98                         } catch { }
99
100                         return null;
101                 }
102         }
103
104         abstract class BaseData
105         {
106                 protected XmlDocument document;
107                 protected XmlNode parent;
108
109                 protected BaseData (XmlDocument doc, XmlNode parent)
110                 {
111                         this.document = doc;
112                         this.parent = parent;
113                 }
114
115                 public abstract void DoOutput ();
116
117                 protected void AddAttribute (XmlNode node, string name, string value)
118                 {
119                         XmlAttribute attr = document.CreateAttribute (name);
120                         attr.Value = value;
121                         node.Attributes.Append (attr);
122                 }
123
124                 public static bool IsMonoTODOAttribute (string s)
125                 {
126                         if (s == null)
127                                 return false;
128                         if (//s.EndsWith ("MonoTODOAttribute") ||
129                             s.EndsWith ("MonoDocumentationNoteAttribute") ||
130                             s.EndsWith ("MonoExtensionAttribute") ||
131 //                          s.EndsWith ("MonoInternalNoteAttribute") ||
132                             s.EndsWith ("MonoLimitationAttribute") ||
133                             s.EndsWith ("MonoNotSupportedAttribute"))
134                                 return true;
135                         return s.EndsWith ("TODOAttribute");
136                 }
137         }
138
139         class AssemblyData : BaseData
140         {
141                 Assembly ass;
142                 
143                 public AssemblyData (XmlDocument document, XmlNode parent, Assembly ass)
144                         : base (document, parent)
145                 {
146                         this.ass = ass;
147                 }
148
149                 public override void DoOutput ()
150                 {
151                         if (document == null)
152                                 throw new InvalidOperationException ("Document not set");
153
154                         XmlNode nassembly = document.CreateElement ("assembly", null);
155                         AssemblyName aname = ass.GetName ();
156                         AddAttribute (nassembly, "name", aname.Name);
157                         AddAttribute (nassembly, "version", aname.Version.ToString ());
158                         parent.AppendChild (nassembly);
159                         AttributeData.OutputAttributes (document, nassembly, ass.GetCustomAttributes (false));
160                         Type [] types = ass.GetExportedTypes ();
161                         if (types == null || types.Length == 0)
162                                 return;
163
164                         Array.Sort (types, TypeComparer.Default);
165
166                         XmlNode nss = document.CreateElement ("namespaces", null);
167                         nassembly.AppendChild (nss);
168
169                         string currentNS = "$%&$&";
170                         XmlNode ns = null;
171                         XmlNode classes = null;
172                         foreach (Type t in types) {
173                                 if (t.Namespace == null || t.Namespace == "")
174                                         continue;
175
176                                 if (t.IsNotPublic)
177                                         continue;
178
179                                 if (t.IsNestedPublic || t.IsNestedAssembly || t.IsNestedFamANDAssem ||
180                                         t.IsNestedFamORAssem || t.IsNestedPrivate)
181                                         continue;
182
183                                 if (t.DeclaringType != null)
184                                         continue; // enforce !nested
185                                 
186                                 if (t.Namespace != currentNS) {
187                                         currentNS = t.Namespace;
188                                         ns = document.CreateElement ("namespace", null);
189                                         AddAttribute (ns, "name", currentNS);
190                                         nss.AppendChild (ns);
191                                         classes = document.CreateElement ("classes", null);
192                                         ns.AppendChild (classes);
193                                 }
194                                 
195                                 TypeData bd = new TypeData (document, classes, t);
196                                 bd.DoOutput ();
197                         }
198                 }
199         }
200
201         abstract class MemberData : BaseData
202         {
203                 MemberInfo [] members;
204
205                 public MemberData (XmlDocument document, XmlNode parent, MemberInfo [] members)
206                         : base (document, parent)
207                 {
208                         this.members = members;
209                 }
210
211                 public override void DoOutput ()
212                 {
213                         XmlNode mclass = document.CreateElement (ParentTag, null);
214                         parent.AppendChild (mclass);
215
216                         foreach (MemberInfo member in members) {
217                                 XmlNode mnode = document.CreateElement (Tag, null);
218                                 mclass.AppendChild (mnode);
219                                 AddAttribute (mnode, "name", GetName (member));
220                                 if (!NoMemberAttributes)
221                                         AddAttribute (mnode, "attrib", GetMemberAttributes (member));
222
223                                 AttributeData.OutputAttributes (document, mnode,
224                                                                 member.GetCustomAttributes (false));
225
226                                 AddExtraData (mnode, member);
227                         }
228                 }
229
230                 protected virtual void AddExtraData (XmlNode p, MemberInfo member)
231                 {
232                 }
233
234                 protected virtual string GetName (MemberInfo member)
235                 {
236                         return "NoNAME";
237                 }
238
239                 protected virtual string GetMemberAttributes (MemberInfo member)
240                 {
241                         return null;
242                 }
243
244                 public virtual bool NoMemberAttributes {
245                         get { return false; }
246                         set {}
247                 }
248
249                 public virtual string ParentTag {
250                         get { return "NoPARENTTAG"; }
251                 }
252                 
253                 public virtual string Tag {
254                         get { return "NoTAG"; }
255                 }
256         }
257
258         class TypeData : MemberData
259         {
260                 Type type;
261                 const BindingFlags flags = BindingFlags.Public | BindingFlags.Static |
262                                                 BindingFlags.Instance | BindingFlags.DeclaredOnly | 
263                                                 BindingFlags.NonPublic;
264                 
265                 public TypeData (XmlDocument document, XmlNode parent, Type type)
266                         : base (document, parent, null)
267                 {
268                         this.type = type;
269                 }
270
271                 public override void DoOutput ()
272                 {
273                         if (document == null)
274                                 throw new InvalidOperationException ("Document not set");
275
276                         XmlNode nclass = document.CreateElement ("class", null);
277                         AddAttribute (nclass, "name", type.Name);
278                         string classType = GetClassType (type);
279                         AddAttribute (nclass, "type", classType);
280
281                         if (type.BaseType != null)
282                                 AddAttribute (nclass, "base", type.BaseType.ToString ());
283
284                         if (type.IsSealed)
285                                 AddAttribute (nclass, "sealed", "true");
286
287                         if (type.IsAbstract)
288                                 AddAttribute (nclass, "abstract", "true");
289
290                         if (type.IsSerializable)
291                                 AddAttribute (nclass, "serializable", "true");
292
293                         string charSet = GetCharSet (type);
294                         AddAttribute (nclass, "charset", charSet);
295
296                         string layout = GetLayout (type);
297                         if (layout != null)
298                                 AddAttribute (nclass, "layout", layout);
299
300                         parent.AppendChild (nclass);
301                         
302                         AttributeData.OutputAttributes (document, nclass, type.GetCustomAttributes (false));
303
304                         Type [] interfaces = type.GetInterfaces ();
305                         if (interfaces != null && interfaces.Length > 0) {
306                                 XmlNode ifaces = document.CreateElement ("interfaces", null);
307                                 nclass.AppendChild (ifaces);
308                                 foreach (Type t in interfaces) {
309                                         if (!t.IsPublic) {
310                                                 // we're only interested in public interfaces
311                                                 continue;
312                                         }
313                                         XmlNode iface = document.CreateElement ("interface", null);
314                                         AddAttribute (iface, "name", t.ToString ());
315                                         ifaces.AppendChild (iface);
316                                 }
317                         }
318
319 #if NET_2_0
320                         // Generic constraints
321                         Type [] gargs = type.GetGenericArguments ();
322                         XmlElement ngeneric = (gargs.Length == 0) ? null :
323                                 document.CreateElement ("generic-type-constraints");
324                         foreach (Type garg in gargs) {
325                                 Type [] csts = garg.GetGenericParameterConstraints ();
326                                 if (csts.Length == 0 || csts [0] == typeof (object))
327                                         continue;
328                                 XmlElement el = document.CreateElement ("generic-type-constraint");
329                                 el.SetAttribute ("name", garg.ToString ());
330                                 el.SetAttribute ("generic-attribute",
331                                         garg.GenericParameterAttributes.ToString ());
332                                 ngeneric.AppendChild (el);
333                                 foreach (Type ct in csts) {
334                                         XmlElement cel = document.CreateElement ("type");
335                                         cel.AppendChild (document.CreateTextNode (ct.FullName));
336                                         el.AppendChild (cel);
337                                 }
338                         }
339                         if (ngeneric != null && ngeneric.FirstChild != null)
340                                 nclass.AppendChild (ngeneric);
341 #endif
342
343                         ArrayList members = new ArrayList ();
344
345                         FieldInfo[] fields = GetFields (type);
346                         if (fields.Length > 0) {
347                                 Array.Sort (fields, MemberInfoComparer.Default);
348                                 FieldData fd = new FieldData (document, nclass, fields);
349                                 // Special case for enum fields
350                                 if (classType == "enum") {
351                                         string etype = fields [0].GetType ().ToString ();
352                                         AddAttribute (nclass, "enumtype", etype);
353                                 }
354                                 members.Add (fd);
355                         }
356
357                         ConstructorInfo [] ctors = GetConstructors (type);
358                         if (ctors.Length > 0) {
359                                 Array.Sort (ctors, MemberInfoComparer.Default);
360                                 members.Add (new ConstructorData (document, nclass, ctors));
361                         }
362
363                         PropertyInfo[] properties = GetProperties (type);
364                         if (properties.Length > 0) {
365                                 Array.Sort (properties, MemberInfoComparer.Default);
366                                 members.Add (new PropertyData (document, nclass, properties));
367                         }
368
369                         EventInfo [] events = GetEvents (type);
370                         if (events.Length > 0) {
371                                 Array.Sort (events, MemberInfoComparer.Default);
372                                 members.Add (new EventData (document, nclass, events));
373                         }
374
375                         MethodInfo [] methods = GetMethods (type);
376                         if (methods.Length > 0) {
377                                 Array.Sort (methods, MemberInfoComparer.Default);
378                                 members.Add (new MethodData (document, nclass, methods));
379                         }
380
381                         foreach (MemberData md in members)
382                                 md.DoOutput ();
383
384                         Type [] nested = type.GetNestedTypes (BindingFlags.Public | BindingFlags.NonPublic);
385                         if (nested != null && nested.Length > 0) {
386                                 bool add_nested = false;
387                                 foreach (Type t in nested) {
388                                         if (t.IsNestedPublic || t.IsNestedFamily || t.IsNestedFamORAssem) {
389                                                 add_nested = true;
390                                                 break;
391                                         }
392                                 }
393
394                                 if (add_nested) {
395                                         XmlNode classes = document.CreateElement ("classes", null);
396                                         nclass.AppendChild (classes);
397                                         foreach (Type t in nested) {
398                                                 if (t.IsNestedPublic || t.IsNestedFamily || t.IsNestedFamORAssem) {
399                                                         TypeData td = new TypeData (document, classes, t);
400                                                         td.DoOutput ();
401                                                 }
402                                         }
403                                 }
404                         }
405                 }
406
407                 protected override string GetMemberAttributes (MemberInfo member)
408                 {
409                         if (member != type)
410                                 throw new InvalidOperationException ("odd");
411                                 
412                         return ((int) type.Attributes).ToString (CultureInfo.InvariantCulture);
413                 }
414
415                 public static bool MustDocumentMethod(MethodBase method)
416                 {
417                         // All other methods
418                         return (method.IsPublic || method.IsFamily || method.IsFamilyOrAssembly);
419                 }
420
421                 static string GetClassType (Type t)
422                 {
423                         if (t.IsEnum)
424                                 return "enum";
425
426                         if (t.IsValueType)
427                                 return "struct";
428
429                         if (t.IsInterface)
430                                 return "interface";
431
432                         if (typeof (Delegate).IsAssignableFrom (t))
433                                 return "delegate";
434
435                         return "class";
436                 }
437
438                 private static string GetCharSet (Type type)
439                 {
440                         if (type.IsAnsiClass)
441                                 return CharSet.Ansi.ToString (CultureInfo.InvariantCulture);
442
443                         if (type.IsAutoClass)
444                                 return CharSet.Auto.ToString (CultureInfo.InvariantCulture);
445
446                         if (type.IsUnicodeClass)
447                                 return CharSet.Unicode.ToString (CultureInfo.InvariantCulture);
448
449                         return CharSet.None.ToString (CultureInfo.InvariantCulture);
450                 }
451
452                 private static string GetLayout (Type type)
453                 {
454                         if (type.IsAutoLayout)
455                                 return LayoutKind.Auto.ToString (CultureInfo.InvariantCulture);
456
457                         if (type.IsExplicitLayout)
458                                 return LayoutKind.Explicit.ToString (CultureInfo.InvariantCulture);
459
460                         if (type.IsLayoutSequential)
461                                 return LayoutKind.Sequential.ToString (CultureInfo.InvariantCulture);
462
463                         return null;
464                 }
465
466                 private FieldInfo[] GetFields (Type type)
467                 {
468                         ArrayList list = new ArrayList ();
469
470                         FieldInfo[] fields = type.GetFields (flags);
471                         foreach (FieldInfo field in fields) {
472                                 if (field.IsSpecialName)
473                                         continue;
474
475                                 // we're only interested in public or protected members
476                                 if (!field.IsPublic && !field.IsFamily && !field.IsFamilyOrAssembly)
477                                         continue;
478
479                                 list.Add (field);
480                         }
481
482                         return (FieldInfo[]) list.ToArray (typeof (FieldInfo));
483                 }
484
485                 internal static PropertyInfo[] GetProperties (Type type)
486                 {
487                         ArrayList list = new ArrayList ();
488
489                         PropertyInfo[] properties = type.GetProperties (flags);
490                         foreach (PropertyInfo property in properties) {
491                                 MethodInfo getMethod = null;
492                                 MethodInfo setMethod = null;
493
494                                 if (property.CanRead) {
495                                         try { getMethod = property.GetGetMethod (true); }
496                                         catch (System.Security.SecurityException) { }
497                                 }
498                                 if (property.CanWrite) {
499                                         try { setMethod = property.GetSetMethod (true); }
500                                         catch (System.Security.SecurityException) { }
501                                 }
502
503                                 bool hasGetter = (getMethod != null) && MustDocumentMethod (getMethod);
504                                 bool hasSetter = (setMethod != null) && MustDocumentMethod (setMethod);
505
506                                 // if neither the getter or setter should be documented, then
507                                 // skip the property
508                                 if (!hasGetter && !hasSetter) {
509                                         continue;
510                                 }
511
512                                 list.Add (property);
513                         }
514
515                         return (PropertyInfo[]) list.ToArray (typeof (PropertyInfo));
516                 }
517
518                 private MethodInfo[] GetMethods (Type type)
519                 {
520                         ArrayList list = new ArrayList ();
521
522                         MethodInfo[] methods = type.GetMethods (flags);
523                         foreach (MethodInfo method in methods) {
524                                 if (method.IsSpecialName && !method.Name.StartsWith ("op_"))
525                                         continue;
526
527                                 // we're only interested in public or protected members
528                                 if (!MustDocumentMethod(method))
529                                         continue;
530
531                                 list.Add (method);
532                         }
533
534                         return (MethodInfo[]) list.ToArray (typeof (MethodInfo));
535                 }
536
537                 private ConstructorInfo[] GetConstructors (Type type)
538                 {
539                         ArrayList list = new ArrayList ();
540
541                         ConstructorInfo[] ctors = type.GetConstructors (flags);
542                         foreach (ConstructorInfo constructor in ctors) {
543                                 // we're only interested in public or protected members
544                                 if (!constructor.IsPublic && !constructor.IsFamily && !constructor.IsFamilyOrAssembly)
545                                         continue;
546
547                                 list.Add (constructor);
548                         }
549
550                         return (ConstructorInfo[]) list.ToArray (typeof (ConstructorInfo));
551                 }
552
553                 private EventInfo[] GetEvents (Type type)
554                 {
555                         ArrayList list = new ArrayList ();
556
557                         EventInfo[] events = type.GetEvents (flags);
558                         foreach (EventInfo eventInfo in events) {
559                                 MethodInfo addMethod = eventInfo.GetAddMethod (true);
560
561                                 if (addMethod == null || !MustDocumentMethod (addMethod))
562                                         continue;
563
564                                 list.Add (eventInfo);
565                         }
566
567                         return (EventInfo[]) list.ToArray (typeof (EventInfo));
568                 }
569         }
570
571         class FieldData : MemberData
572         {
573                 public FieldData (XmlDocument document, XmlNode parent, FieldInfo [] members)
574                         : base (document, parent, members)
575                 {
576                 }
577
578                 protected override string GetName (MemberInfo member)
579                 {
580                         FieldInfo field = (FieldInfo) member;
581                         return field.Name;
582                 }
583
584                 protected override string GetMemberAttributes (MemberInfo member)
585                 {
586                         FieldInfo field = (FieldInfo) member;
587                         return ((int) field.Attributes).ToString (CultureInfo.InvariantCulture);
588                 }
589
590                 protected override void AddExtraData (XmlNode p, MemberInfo member)
591                 {
592                         base.AddExtraData (p, member);
593                         FieldInfo field = (FieldInfo) member;
594                         AddAttribute (p, "fieldtype", field.FieldType.ToString ());
595
596                         if (field.IsLiteral) {
597                                 object value = field.GetValue (null);
598                                 string stringValue = null;
599                                 if (value is Enum) {
600                                         // FIXME: when Mono bug #60090 has been
601                                         // fixed, we should just be able to use
602                                         // Convert.ToString
603                                         stringValue = ((Enum) value).ToString ("D", CultureInfo.InvariantCulture);
604                                 } else {
605                                         stringValue = Convert.ToString (value, CultureInfo.InvariantCulture);
606                                 }
607
608                                 if (stringValue != null)
609                                         AddAttribute (p, "value", stringValue);
610                         }
611                 }
612
613                 public override string ParentTag {
614                         get { return "fields"; }
615                 }
616
617                 public override string Tag {
618                         get { return "field"; }
619                 }
620         }
621
622         class PropertyData : MemberData
623         {
624                 public PropertyData (XmlDocument document, XmlNode parent, PropertyInfo [] members)
625                         : base (document, parent, members)
626                 {
627                 }
628
629                 protected override string GetName (MemberInfo member)
630                 {
631                         PropertyInfo prop = (PropertyInfo) member;
632                         return prop.Name;
633                 }
634
635                 protected override void AddExtraData (XmlNode p, MemberInfo member)
636                 {
637                         base.AddExtraData (p, member);
638                         PropertyInfo prop = (PropertyInfo) member;
639                         Type t = prop.PropertyType;
640                         AddAttribute (p, "ptype", prop.PropertyType.ToString ());
641                         MethodInfo _get = prop.GetGetMethod (true);
642                         MethodInfo _set = prop.GetSetMethod (true);
643                         bool haveGet = (_get != null && TypeData.MustDocumentMethod(_get));
644                         bool haveSet = (_set != null && TypeData.MustDocumentMethod(_set));
645                         MethodInfo [] methods;
646
647                         if (haveGet && haveSet) {
648                                 methods = new MethodInfo [] {_get, _set};
649                         } else if (haveGet) {
650                                 methods = new MethodInfo [] {_get};
651                         } else if (haveSet) {
652                                 methods = new MethodInfo [] {_set};
653                         } else {
654                                 //odd
655                                 return;
656                         }
657
658                         string parms = Parameters.GetSignature (methods [0].GetParameters ());
659                         AddAttribute (p, "params", parms);
660
661                         MethodData data = new MethodData (document, p, methods);
662                         //data.NoMemberAttributes = true;
663                         data.DoOutput ();
664                 }
665
666                 protected override string GetMemberAttributes (MemberInfo member)
667                 {
668                         PropertyInfo prop = (PropertyInfo) member;
669                         return ((int) prop.Attributes & (0xFFFFFFFF ^ (int) PropertyAttributes.ReservedMask)).ToString (CultureInfo.InvariantCulture);
670                 }
671
672                 public override string ParentTag {
673                         get { return "properties"; }
674                 }
675
676                 public override string Tag {
677                         get { return "property"; }
678                 }
679         }
680
681         class EventData : MemberData
682         {
683                 public EventData (XmlDocument document, XmlNode parent, EventInfo [] members)
684                         : base (document, parent, members)
685                 {
686                 }
687
688                 protected override string GetName (MemberInfo member)
689                 {
690                         EventInfo evt = (EventInfo) member;
691                         return evt.Name;
692                 }
693
694                 protected override string GetMemberAttributes (MemberInfo member)
695                 {
696                         EventInfo evt = (EventInfo) member;
697                         return ((int) evt.Attributes).ToString (CultureInfo.InvariantCulture);
698                 }
699
700                 protected override void AddExtraData (XmlNode p, MemberInfo member)
701                 {
702                         base.AddExtraData (p, member);
703                         EventInfo evt = (EventInfo) member;
704                         AddAttribute (p, "eventtype", evt.EventHandlerType.ToString ());
705                 }
706
707                 public override string ParentTag {
708                         get { return "events"; }
709                 }
710
711                 public override string Tag {
712                         get { return "event"; }
713                 }
714         }
715
716         class MethodData : MemberData
717         {
718                 bool noAtts;
719
720                 public MethodData (XmlDocument document, XmlNode parent, MethodBase [] members)
721                         : base (document, parent, members)
722                 {
723                 }
724
725                 protected override string GetName (MemberInfo member)
726                 {
727                         MethodBase method = (MethodBase) member;
728                         string name = method.Name;
729                         string parms = Parameters.GetSignature (method.GetParameters ());
730 #if NET_2_0
731                         MethodInfo mi = method as MethodInfo;
732                         Type [] genArgs = mi == null ? Type.EmptyTypes :
733                                 mi.GetGenericArguments ();
734                         if (genArgs.Length > 0) {
735                                 string [] genArgNames = new string [genArgs.Length];
736                                 for (int i = 0; i < genArgs.Length; i++) {
737                                         genArgNames [i] = genArgs [i].Name;
738                                         string genArgCsts = String.Empty;
739                                         Type [] gcs = genArgs [i].GetGenericParameterConstraints ();
740                                         if (gcs.Length > 0) {
741                                                 string [] gcNames = new string [gcs.Length];
742                                                 for (int g = 0; g < gcs.Length; g++)
743                                                         gcNames [g] = gcs [g].FullName;
744                                                 genArgCsts = String.Concat (
745                                                         "(",
746                                                         string.Join (", ", gcNames),
747                                                         ") ",
748                                                         genArgNames [i]);
749                                         }
750                                         else
751                                                 genArgCsts = genArgNames [i];
752                                         if ((genArgs [i].GenericParameterAttributes & GenericParameterAttributes.ReferenceTypeConstraint) != 0)
753                                                 genArgCsts = "class " + genArgCsts;
754                                         else if ((genArgs [i].GenericParameterAttributes & GenericParameterAttributes.NotNullableValueTypeConstraint) != 0)
755                                                 genArgCsts = "struct " + genArgCsts;
756                                         genArgNames [i] = genArgCsts;
757                                 }
758                                 return String.Format ("{0}<{2}>({1})",
759                                         name,
760                                         parms,
761                                         string.Join (",", genArgNames));
762                         }
763 #endif
764                         return String.Format ("{0}({1})", name, parms);
765                 }
766
767                 protected override string GetMemberAttributes (MemberInfo member)
768                 {
769                         MethodBase method = (MethodBase) member;
770                         return ((int)( method.Attributes & ~MethodAttributes.ReservedMask)).ToString (CultureInfo.InvariantCulture);
771                 }
772
773                 protected override void AddExtraData (XmlNode p, MemberInfo member)
774                 {
775                         base.AddExtraData (p, member);
776
777                         ParameterData parms = new ParameterData (document, p, 
778                                 ((MethodBase) member).GetParameters ());
779                         parms.DoOutput ();
780
781                         if (!(member is MethodBase))
782                                 return;
783
784                         MethodBase mbase = (MethodBase) member;
785
786                         if (mbase.IsAbstract)
787                                 AddAttribute (p, "abstract", "true");
788                         if (mbase.IsVirtual)
789                                 AddAttribute (p, "virtual", "true");
790                         if (mbase.IsFinal)
791                                 AddAttribute (p, "final", "true");
792                         if (mbase.IsStatic)
793                                 AddAttribute (p, "static", "true");
794
795                         if (!(member is MethodInfo))
796                                 return;
797
798                         MethodInfo method = (MethodInfo) member;
799                         AddAttribute (p, "returntype", method.ReturnType.ToString ());
800
801                         AttributeData.OutputAttributes (document, p,
802                                 method.ReturnTypeCustomAttributes.GetCustomAttributes (false));
803 #if NET_2_0
804                         // Generic constraints
805                         Type [] gargs = method.GetGenericArguments ();
806                         XmlElement ngeneric = (gargs.Length == 0) ? null :
807                                 document.CreateElement ("generic-method-constraints");
808                         foreach (Type garg in gargs) {
809                                 Type [] csts = garg.GetGenericParameterConstraints ();
810                                 if (csts.Length == 0 || csts [0] == typeof (object))
811                                         continue;
812                                 XmlElement el = document.CreateElement ("generic-method-constraint");
813                                 el.SetAttribute ("name", garg.ToString ());
814                                 el.SetAttribute ("generic-attribute",
815                                         garg.GenericParameterAttributes.ToString ());
816                                 ngeneric.AppendChild (el);
817                                 foreach (Type ct in csts) {
818                                         XmlElement cel = document.CreateElement ("type");
819                                         cel.AppendChild (document.CreateTextNode (ct.FullName));
820                                         el.AppendChild (cel);
821                                 }
822                         }
823                         if (ngeneric != null && ngeneric.FirstChild != null)
824                                 p.AppendChild (ngeneric);
825 #endif
826
827                 }
828
829                 public override bool NoMemberAttributes {
830                         get { return noAtts; }
831                         set { noAtts = value; }
832                 }
833                 
834                 public override string ParentTag {
835                         get { return "methods"; }
836                 }
837
838                 public override string Tag {
839                         get { return "method"; }
840                 }
841         }
842
843         class ConstructorData : MethodData
844         {
845                 public ConstructorData (XmlDocument document, XmlNode parent, ConstructorInfo [] members)
846                         : base (document, parent, members)
847                 {
848                 }
849
850                 public override string ParentTag {
851                         get { return "constructors"; }
852                 }
853
854                 public override string Tag {
855                         get { return "constructor"; }
856                 }
857         }
858
859         class ParameterData : BaseData
860         {
861                 private ParameterInfo[] parameters;
862
863                 public ParameterData (XmlDocument document, XmlNode parent, ParameterInfo[] parameters)
864                         : base (document, parent)
865                 {
866                         this.parameters = parameters;
867                 }
868
869                 public override void DoOutput ()
870                 {
871                         XmlNode parametersNode = document.CreateElement ("parameters", null);
872                         parent.AppendChild (parametersNode);
873
874                         foreach (ParameterInfo parameter in parameters) {
875                                 XmlNode paramNode = document.CreateElement ("parameter", null);
876                                 parametersNode.AppendChild (paramNode);
877                                 AddAttribute (paramNode, "name", parameter.Name);
878                                 AddAttribute (paramNode, "position", parameter.Position.ToString(CultureInfo.InvariantCulture));
879                                 AddAttribute (paramNode, "attrib", ((int) parameter.Attributes).ToString());
880
881                                 string direction = "in";
882
883                                 if (parameter.ParameterType.IsByRef) {
884                                         direction = parameter.IsOut ? "out" : "ref";
885                                 }
886
887                                 Type t = parameter.ParameterType;
888                                 AddAttribute (paramNode, "type", t.ToString ());
889
890                                 if (parameter.IsOptional) {
891                                         AddAttribute (paramNode, "optional", "true");
892                                         if (parameter.DefaultValue != System.DBNull.Value)
893                                                 AddAttribute (paramNode, "defaultValue", (parameter.DefaultValue == null) ? "NULL" : parameter.DefaultValue.ToString ());
894                                 }
895
896                                 if (direction != "in")
897                                         AddAttribute (paramNode, "direction", direction);
898
899                                 AttributeData.OutputAttributes (document, paramNode, parameter.GetCustomAttributes (false));
900                         }
901                 }
902         }
903
904         class AttributeData : BaseData
905         {
906                 object [] atts;
907
908                 AttributeData (XmlDocument doc, XmlNode parent, object[] attributes)
909                         : base (doc, parent)
910                 {
911                         atts = attributes;
912                 }
913
914                 public override void DoOutput ()
915                 {
916                         if (document == null)
917                                 throw new InvalidOperationException ("Document not set");
918
919                         if (atts == null || atts.Length == 0)
920                                 return;
921
922                         XmlNode natts = parent.SelectSingleNode("attributes");
923                         if (natts == null) {
924                                 natts = document.CreateElement ("attributes", null);
925                                 parent.AppendChild (natts);
926                         }
927
928                         for (int i = 0; i < atts.Length; ++i) {
929                                 Type t = atts [i].GetType ();
930                                 if (!t.IsPublic && !IsMonoTODOAttribute (t.Name))
931                                         continue;
932
933                                 // we ignore attributes that inherit from SecurityAttribute on purpose as they:
934                                 // * aren't part of GetCustomAttributes in Fx 1.0/1.1;
935                                 // * are encoded differently and in a different metadata table; and
936                                 // * won't ever exactly match MS implementation (from a syntax pov)
937                                 if (t.IsSubclassOf (typeof (SecurityAttribute)))
938                                         continue;
939
940                                 XmlNode node = document.CreateElement ("attribute");
941                                 AddAttribute (node, "name", t.ToString ());
942
943                                 XmlNode properties = null;
944                                 foreach (PropertyInfo pi in TypeData.GetProperties (t)) {
945                                         if (pi.Name == "TypeId")
946                                                 continue;
947
948                                         if (properties == null) {
949                                                 properties = node.AppendChild (document.CreateElement ("properties"));
950                                         }
951
952                                         try {
953                                                 object o = pi.GetValue (atts [i], null);
954
955                                                 XmlNode n = properties.AppendChild (document.CreateElement ("property"));
956                                                 AddAttribute (n, "name", pi.Name);
957
958                                                 if (o == null) {
959                                                         AddAttribute (n, "null", "true");
960                                                         continue;
961                                                 }
962
963                                                 string value = o.ToString ();
964                                                 if (t == typeof (GuidAttribute))
965                                                         value = value.ToUpper ();
966
967                                                 AddAttribute (n, "value", value);
968                                         }
969                                         catch (TargetInvocationException) {
970                                                 continue;
971                                         }
972                                 }
973
974                                 natts.AppendChild (node);
975                         }
976                 }
977
978                 public static void OutputAttributes (XmlDocument doc, XmlNode parent, object[] attributes)
979                 {
980                         AttributeData ad = new AttributeData (doc, parent, attributes);
981                         ad.DoOutput ();
982                 }
983
984                 private static bool MustDocumentAttribute (Type attributeType)
985                 {
986                         // only document MonoTODOAttribute and public attributes
987                         return attributeType.IsPublic || IsMonoTODOAttribute (attributeType.Name);
988                 }
989         }
990
991         class Parameters
992         {
993                 private Parameters () {}
994
995                 public static string GetSignature (ParameterInfo [] infos)
996                 {
997                         if (infos == null || infos.Length == 0)
998                                 return "";
999
1000                         StringBuilder sb = new StringBuilder ();
1001                         foreach (ParameterInfo info in infos) {
1002                                 string modifier;
1003                                 if (info.IsIn)
1004                                         modifier = "in ";
1005                                 else if (info.IsRetval)
1006                                         modifier = "ref ";
1007                                 else if (info.IsOut)
1008                                         modifier = "out ";
1009                                 else
1010                                         modifier = "";
1011
1012                                 string type_name = info.ParameterType.ToString ().Replace ('<', '[').Replace ('>', ']');
1013                                 sb.AppendFormat ("{0}{1}, ", modifier, type_name);
1014                         }
1015
1016                         sb.Length -= 2; // remove ", "
1017                         return sb.ToString ();
1018                 }
1019
1020         }
1021         
1022         class TypeComparer : IComparer
1023         {
1024                 public static TypeComparer Default = new TypeComparer ();
1025
1026                 public int Compare (object a, object b)
1027                 {
1028                         Type ta = (Type) a;
1029                         Type tb = (Type) b;
1030                         int result = String.Compare (ta.Namespace, tb.Namespace);
1031                         if (result != 0)
1032                                 return result;
1033
1034                         return String.Compare (ta.Name, tb.Name);
1035                 }
1036         }
1037
1038         class MemberInfoComparer : IComparer
1039         {
1040                 public static MemberInfoComparer Default = new MemberInfoComparer ();
1041
1042                 public int Compare (object a, object b)
1043                 {
1044                         MemberInfo ma = (MemberInfo) a;
1045                         MemberInfo mb = (MemberInfo) b;
1046                         return String.Compare (ma.Name, mb.Name);
1047                 }
1048         }
1049
1050         class MethodBaseComparer : IComparer
1051         {
1052                 public static MethodBaseComparer Default = new MethodBaseComparer ();
1053
1054                 public int Compare (object a, object b)
1055                 {
1056                         MethodBase ma = (MethodBase) a;
1057                         MethodBase mb = (MethodBase) b;
1058                         int res = String.Compare (ma.Name, mb.Name);
1059                         if (res != 0)
1060                                 return res;
1061
1062                         ParameterInfo [] pia = ma.GetParameters ();
1063                         ParameterInfo [] pib = mb.GetParameters ();
1064                         if (pia.Length != pib.Length)
1065                                 return pia.Length - pib.Length;
1066
1067                         string siga = Parameters.GetSignature (pia);
1068                         string sigb = Parameters.GetSignature (pib);
1069                         return String.Compare (siga, sigb);
1070                 }
1071         }
1072 }
1073