Only set the attached flag when a client attaches (#3490)
[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-2008 Novell, Inc (http://www.novell.com)
8 //
9
10 using System;
11 using System.Collections;
12 using System.Collections.Generic;
13 using System.Globalization;
14 using System.Linq;
15 using System.Runtime.CompilerServices;
16 using System.Runtime.InteropServices;
17 using System.Security.Permissions;
18 using System.Text;
19 using System.Xml;
20
21 using Mono.Cecil;
22 using Mono.Cecil.Cil;
23 using System.IO;
24
25 namespace CorCompare
26 {
27         public class Driver
28         {
29                 public static int Main (string [] args)
30                 {
31                         bool showHelp = false;
32                         AbiMode = false;
33                         FollowForwarders = false;
34                         string output = null;
35
36                         var acoll = new AssemblyCollection ();
37
38                         var options = new Mono.Options.OptionSet {
39                                 "usage: mono-api-info [OPTIONS+] ASSEMBLY+",
40                                 "",
41                                 "Expose IL structure of CLR assemblies as XML.",
42                                 "",
43                                 "Available Options:",
44                                 { "abi",
45                                         "Generate ABI, not API; contains only classes with instance fields which are not [NonSerialized].",
46                                         v => AbiMode = v != null },
47                                 { "f|follow-forwarders",
48                                         "Follow type forwarders.",
49                                         v => FollowForwarders = v != null },
50                                 { "d|L|lib|search-directory=",
51                                         "Check for assembly references in {DIRECTORY}.",
52                                         v => TypeHelper.Resolver.AddSearchDirectory (v) },
53                                 { "r=",
54                                         "Read and register the file {ASSEMBLY}, and add the directory containing ASSEMBLY to the search path.",
55                                         v => TypeHelper.Resolver.ResolveFile (v) },
56                                 { "o=",
57                                         "The output file. If not specified the output will be written to stdout.",
58                                         v => output = v },
59                                 { "h|?|help",
60                                         "Show this message and exit.",
61                                         v => showHelp = v != null },
62                                 { "contract-api",
63                                         "Produces contract API with all members at each level of inheritance hierarchy",
64                                         v => FullAPISet = v != null },
65                         };
66
67                         var asms = options.Parse (args);
68
69                         if (showHelp || asms.Count == 0) {
70                                 options.WriteOptionDescriptions (Console.Out);
71                                 Console.WriteLine ();
72                                 return showHelp? 0 :1;
73                         }
74
75                         string windir = Environment.GetFolderPath(Environment.SpecialFolder.Windows);
76                         string pf = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles);
77                         TypeHelper.Resolver.AddSearchDirectory (Path.Combine (windir, @"assembly\GAC\MSDATASRC\7.0.3300.0__b03f5f7f11d50a3a"));
78
79                         foreach (string arg in asms) {
80                                 acoll.Add (arg);
81
82                                 if (arg.Contains ("v3.0")) {
83                                         TypeHelper.Resolver.AddSearchDirectory (Path.Combine (windir, @"Microsoft.NET\Framework\v2.0.50727"));
84                                 } else if (arg.Contains ("v3.5")) {
85                                         TypeHelper.Resolver.AddSearchDirectory (Path.Combine (windir, @"Microsoft.NET\Framework\v2.0.50727"));
86                                         TypeHelper.Resolver.AddSearchDirectory (Path.Combine (windir, @"Microsoft.NET\Framework\v3.0\Windows Communication Foundation"));
87                                 } else if (arg.Contains ("v4.0")) {
88                                         if (arg.Contains ("Silverlight")) {
89                                                 TypeHelper.Resolver.AddSearchDirectory (Path.Combine (pf, @"Microsoft Silverlight\4.0.51204.0"));
90                                         } else {
91                                                 TypeHelper.Resolver.AddSearchDirectory (Path.Combine (windir, @"Microsoft.NET\Framework\v4.0.30319"));
92                                                 TypeHelper.Resolver.AddSearchDirectory (Path.Combine (windir, @"Microsoft.NET\Framework\v4.0.30319\WPF"));
93                                         }
94                                 } else {
95                                         TypeHelper.Resolver.AddSearchDirectory (Path.GetDirectoryName (arg));
96                                 }
97                         }
98
99                         StreamWriter outputStream = null;
100                         if (!string.IsNullOrEmpty (output))
101                                 outputStream = new StreamWriter (output);
102                         try {
103                                 TextWriter outStream = outputStream ?? Console.Out;
104                                 var settings = new XmlWriterSettings ();
105                                 settings.Indent = true;
106                                 var textWriter = XmlWriter.Create (outStream, settings);
107                                 var writer = new WellFormedXmlWriter (textWriter);
108                                 writer.WriteStartDocument ();
109                                 acoll.Writer = writer;
110                                 acoll.DoOutput ();
111                                 writer.WriteEndDocument ();
112                                 writer.Flush ();
113                         } finally {
114                                 if (outputStream != null)
115                                         outputStream.Dispose ();
116                         }
117                         return 0;
118                 }
119
120                 internal static bool AbiMode { get; private set; }
121                 internal static bool FollowForwarders { get; private set; }
122                 internal static bool FullAPISet { get; set; }
123         }
124
125         public class Utils {
126                 static char[] CharsToCleanup = new char[] { '<', '>', '/' };
127
128                 public static string CleanupTypeName (TypeReference type)
129                 {
130                         return CleanupTypeName (type.FullName);
131                 }
132
133                 public static string CleanupTypeName (string t)
134                 {
135                         if (t.IndexOfAny (CharsToCleanup) == -1)
136                                 return t;
137                         var sb = new StringBuilder (t.Length);
138                         for (int i = 0; i < t.Length; i++) {
139                                 var ch = t [i];
140                                 switch (ch) {
141                                 case '<':
142                                         sb.Append ('[');
143                                         break;
144                                 case '>':
145                                         sb.Append (']');
146                                         break;
147                                 case '/':
148                                         sb.Append ('+');
149                                         break;
150                                 default:
151                                         sb.Append (ch);
152                                         break;
153                                 }
154                         }
155                         return sb.ToString ();
156                 }
157         }
158
159         class AssemblyCollection
160         {
161                 XmlWriter writer;
162                 List<AssemblyDefinition> assemblies = new List<AssemblyDefinition> ();
163
164                 public AssemblyCollection ()
165                 {
166                 }
167
168                 public bool Add (string name)
169                 {
170                         AssemblyDefinition ass = LoadAssembly (name);
171                         if (ass == null) {
172                                 Console.Error.WriteLine ("Cannot load assembly file " + name);
173                                 return false;
174                         }
175
176                         assemblies.Add (ass);
177                         return true;
178                 }
179
180                 public void DoOutput ()
181                 {
182                         if (writer == null)
183                                 throw new InvalidOperationException ("Document not set");
184
185                         writer.WriteStartElement ("assemblies");
186                         foreach (AssemblyDefinition a in assemblies) {
187                                 AssemblyData data = new AssemblyData (writer, a);
188                                 data.DoOutput ();
189                         }
190                         writer.WriteEndElement ();
191                 }
192
193                 public XmlWriter Writer {
194                         set { writer = value; }
195                 }
196
197                 AssemblyDefinition LoadAssembly (string assembly)
198                 {
199                         try {
200                                 if (File.Exists (assembly))
201                                         return TypeHelper.Resolver.ResolveFile (assembly);
202
203                                 return TypeHelper.Resolver.Resolve (assembly);
204                         } catch (Exception e) {
205                                 Console.WriteLine (e);
206                                 return null;
207                         }
208                 }
209         }
210
211         abstract class BaseData
212         {
213                 protected XmlWriter writer;
214
215                 protected BaseData (XmlWriter writer)
216                 {
217                         this.writer = writer;
218                 }
219
220                 public abstract void DoOutput ();
221
222                 protected void AddAttribute (string name, string value)
223                 {
224                         writer.WriteAttributeString (name, value);
225                 }
226         }
227
228         class TypeForwardedToData : BaseData
229         {
230                 AssemblyDefinition ass;
231
232                 public TypeForwardedToData (XmlWriter writer, AssemblyDefinition ass)
233                         : base (writer)
234                 {
235                         this.ass = ass;
236                 }
237
238                 public override void DoOutput ()
239                 {
240                         foreach (ExportedType type in ass.MainModule.ExportedTypes) {
241
242                                 if (((uint)type.Attributes & 0x200000u) == 0)
243                                         continue;
244
245                                 writer.WriteStartElement ("attribute");
246                                 AddAttribute ("name", typeof (TypeForwardedToAttribute).FullName);
247                                 writer.WriteStartElement ("properties");
248                                 writer.WriteStartElement ("property");
249                                 AddAttribute ("name", "Destination");
250                                 AddAttribute ("value", Utils.CleanupTypeName (type.FullName));
251                                 writer.WriteEndElement (); // properties
252                                 writer.WriteEndElement (); // properties
253                                 writer.WriteEndElement (); // attribute
254                         }
255                 }
256
257                 public static void OutputForwarders (XmlWriter writer, AssemblyDefinition ass)
258                 {
259                         TypeForwardedToData tftd = new TypeForwardedToData (writer, ass);
260                         tftd.DoOutput ();
261                 }
262         }
263
264         class AssemblyData : BaseData
265         {
266                 AssemblyDefinition ass;
267
268                 public AssemblyData (XmlWriter writer, AssemblyDefinition ass)
269                         : base (writer)
270                 {
271                         this.ass = ass;
272                 }
273
274                 public override void DoOutput ()
275                 {
276                         if (writer == null)
277                                 throw new InvalidOperationException ("Document not set");
278
279                         writer.WriteStartElement ("assembly");
280                         AssemblyNameDefinition aname = ass.Name;
281                         AddAttribute ("name", aname.Name);
282                         AddAttribute ("version", aname.Version.ToString ());
283
284                         AttributeData.OutputAttributes (writer, ass);
285
286                         var types = new List<TypeDefinition> ();
287                         if (ass.MainModule.Types != null) {
288                                 types.AddRange (ass.MainModule.Types);
289                         }
290
291                         if (Driver.FollowForwarders && ass.MainModule.ExportedTypes != null) {
292                                 foreach (var t in ass.MainModule.ExportedTypes) {
293                                         var forwarded = t.Resolve ();
294                                         if (forwarded == null) {
295                                                 throw new Exception ("Could not resolve forwarded type " + t.FullName + " in " + ass.Name);
296                                         }
297                                         types.Add (forwarded);
298                                 }
299                         }
300
301                         if (types.Count == 0) {
302                                 writer.WriteEndElement (); // assembly
303                                 return;
304                         }
305
306                         types.Sort (TypeReferenceComparer.Default);
307
308                         writer.WriteStartElement ("namespaces");
309
310                         string current_namespace = "$%&$&";
311                         bool in_namespace = false;
312                         foreach (TypeDefinition t in types) {
313                                 if (string.IsNullOrEmpty (t.Namespace))
314                                         continue;
315
316                                 if (!Driver.AbiMode && ((t.Attributes & TypeAttributes.VisibilityMask) != TypeAttributes.Public))
317                                         continue;
318
319                                 if (t.DeclaringType != null)
320                                         continue; // enforce !nested
321
322                                 if (t.Namespace != current_namespace) {
323                                         current_namespace = t.Namespace;
324                                         if (in_namespace) {
325                                                 writer.WriteEndElement (); // classes
326                                                 writer.WriteEndElement (); // namespace
327                                         } else {
328                                                 in_namespace = true;
329                                         }
330                                         writer.WriteStartElement ("namespace");
331                                         AddAttribute ("name", current_namespace);
332                                         writer.WriteStartElement ("classes");
333                                 }
334
335                                 TypeData bd = new TypeData (writer, t);
336                                 bd.DoOutput ();
337
338                         }
339
340                         if (in_namespace) {
341                                 writer.WriteEndElement (); // classes
342                                 writer.WriteEndElement (); // namespace
343                         }
344
345                         writer.WriteEndElement (); // namespaces
346
347                         writer.WriteEndElement (); // assembly
348                 }
349         }
350
351         abstract class MemberData : BaseData
352         {
353                 MemberReference [] members;
354
355                 public MemberData (XmlWriter writer, MemberReference [] members)
356                         : base (writer)
357                 {
358                         this.members = members;
359                 }
360
361                 protected virtual ICustomAttributeProvider GetAdditionalCustomAttributeProvider (MemberReference member)
362                 {
363                         return null;
364                 }
365
366                 public override void DoOutput ()
367                 {
368                         writer.WriteStartElement (ParentTag);
369
370                         foreach (MemberReference member in members) {
371                                 writer.WriteStartElement (Tag);
372                                 AddAttribute ("name", GetName (member));
373                                 if (!NoMemberAttributes)
374                                         AddAttribute ("attrib", GetMemberAttributes (member));
375                                 AddExtraAttributes (member);
376
377                                 AttributeData.OutputAttributes (writer, (ICustomAttributeProvider) member, GetAdditionalCustomAttributeProvider (member));
378
379                                 AddExtraData (member);
380                                 writer.WriteEndElement (); // Tag
381                         }
382
383                         writer.WriteEndElement (); // ParentTag
384                 }
385
386                 protected virtual void AddExtraData (MemberReference memberDefenition)
387                 {
388                 }
389
390                 protected virtual void AddExtraAttributes (MemberReference memberDefinition)
391                 {
392                 }
393
394                 protected virtual string GetName (MemberReference memberDefenition)
395                 {
396                         return "NoNAME";
397                 }
398
399                 protected virtual string GetMemberAttributes (MemberReference memberDefenition)
400                 {
401                         return null;
402                 }
403
404                 public virtual bool NoMemberAttributes {
405                         get { return false; }
406                         set {}
407                 }
408
409                 public virtual string ParentTag {
410                         get { return "NoPARENTTAG"; }
411                 }
412
413                 public virtual string Tag {
414                         get { return "NoTAG"; }
415                 }
416
417                 public static void OutputGenericParameters (XmlWriter writer, IGenericParameterProvider provider)
418                 {
419                         if (provider.GenericParameters.Count == 0)
420                                 return;
421
422                         var gparameters = provider.GenericParameters;
423
424                         writer.WriteStartElement ("generic-parameters");
425
426                         foreach (GenericParameter gp in gparameters) {
427                                 writer.WriteStartElement ("generic-parameter");
428                                 writer.WriteAttributeString ("name", gp.Name);
429                                 writer.WriteAttributeString ("attributes", ((int) gp.Attributes).ToString ());
430
431                                 AttributeData.OutputAttributes (writer, gp);
432
433                                 var constraints = gp.Constraints;
434                                 if (constraints.Count == 0) {
435                                         writer.WriteEndElement (); // generic-parameter
436                                         continue;
437                                 }
438
439                                 writer.WriteStartElement ("generic-parameter-constraints");
440
441                                 foreach (TypeReference constraint in constraints) {
442                                         writer.WriteStartElement ("generic-parameter-constraint");
443                                         writer.WriteAttributeString ("name", Utils.CleanupTypeName (constraint));
444                                         writer.WriteEndElement (); // generic-parameter-constraint
445                                 }
446
447                                 writer.WriteEndElement (); // generic-parameter-constraints
448
449                                 writer.WriteEndElement (); // generic-parameter
450                         }
451
452                         writer.WriteEndElement (); // generic-parameters
453                 }
454         }
455
456         class TypeData : MemberData
457         {
458                 TypeDefinition type;
459
460                 public TypeData (XmlWriter writer, TypeDefinition type)
461                         : base (writer, null)
462                 {
463                         this.type = type;
464                 }
465                 public override void DoOutput ()
466                 {
467                         if (writer == null)
468                                 throw new InvalidOperationException ("Document not set");
469
470                         writer.WriteStartElement ("class");
471                         AddAttribute ("name", type.Name);
472                         string classType = GetClassType (type);
473                         AddAttribute ("type", classType);
474
475                         if (type.BaseType != null)
476                                 AddAttribute ("base", Utils.CleanupTypeName (type.BaseType));
477
478                         if (type.IsSealed)
479                                 AddAttribute ("sealed", "true");
480
481                         if (type.IsAbstract)
482                                 AddAttribute ("abstract", "true");
483
484                         if ( (type.Attributes & TypeAttributes.Serializable) != 0 || type.IsEnum)
485                                 AddAttribute ("serializable", "true");
486
487                         string charSet = GetCharSet (type);
488                         AddAttribute ("charset", charSet);
489
490                         string layout = GetLayout (type);
491                         if (layout != null)
492                                 AddAttribute ("layout", layout);
493
494                         if (type.PackingSize >= 0) {
495                                 AddAttribute ("pack", type.PackingSize.ToString ());
496                         }
497
498                         if (type.ClassSize >= 0) {
499                                 AddAttribute ("size", type.ClassSize.ToString ());
500                         }
501
502                         if (type.IsEnum) {
503                                 var value_type = GetEnumValueField (type);
504                                 if (value_type == null)
505                                         throw new NotSupportedException ();
506
507                                 AddAttribute ("enumtype", Utils.CleanupTypeName (value_type.FieldType));
508                         }
509
510                         AttributeData.OutputAttributes (writer, type);
511
512                         var ifaces =  TypeHelper.GetInterfaces (type).
513                                 Where ((iface) => TypeHelper.IsPublic (iface)). // we're only interested in public interfaces
514                                 OrderBy (s => s.FullName, StringComparer.Ordinal);
515
516                         if (ifaces.Any ()) {
517                                 writer.WriteStartElement ("interfaces");
518                                 foreach (TypeReference iface in ifaces) {
519                                         writer.WriteStartElement ("interface");
520                                         AddAttribute ("name", Utils.CleanupTypeName (iface));
521                                         writer.WriteEndElement (); // interface
522                                 }
523                                 writer.WriteEndElement (); // interfaces
524                         }
525
526                         MemberData.OutputGenericParameters (writer, type);
527
528                         ArrayList members = new ArrayList ();
529
530                         FieldDefinition [] fields = GetFields (type);
531                         if (fields.Length > 0) {
532                                 Array.Sort (fields, MemberReferenceComparer.Default);
533                                 FieldData fd = new FieldData (writer, fields);
534                                 members.Add (fd);
535                         }
536
537                         if (!Driver.AbiMode) {
538
539                                 MethodDefinition [] ctors = GetConstructors (type);
540                                 if (ctors.Length > 0) {
541                                         Array.Sort (ctors, MethodDefinitionComparer.Default);
542                                         members.Add (new ConstructorData (writer, ctors));
543                                 }
544
545                                 PropertyDefinition[] properties = GetProperties (type, Driver.FullAPISet);
546                                 if (properties.Length > 0) {
547                                         Array.Sort (properties, PropertyDefinitionComparer.Default);
548                                         members.Add (new PropertyData (writer, properties));
549                                 }
550
551                                 EventDefinition [] events = GetEvents (type);
552                                 if (events.Length > 0) {
553                                         Array.Sort (events, MemberReferenceComparer.Default);
554                                         members.Add (new EventData (writer, events));
555                                 }
556
557                                 MethodDefinition [] methods = GetMethods (type, Driver.FullAPISet);
558                                 if (methods.Length > 0) {
559                                         Array.Sort (methods, MethodDefinitionComparer.Default);
560                                         members.Add (new MethodData (writer, methods));
561                                 }
562                         }
563
564                         foreach (MemberData md in members)
565                                 md.DoOutput ();
566
567                         var nested = type.NestedTypes;
568                         //remove non public(familiy) and nested in second degree
569                         for (int i = nested.Count - 1; i >= 0; i--) {
570                                 TypeDefinition t = nested [i];
571                                 if ((t.Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedPublic ||
572                                         (t.Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedFamily ||
573                                         (t.Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedFamORAssem) {
574                                         // public
575                                         if (t.DeclaringType == type)
576                                                 continue; // not nested of nested
577                                 }
578
579                                 nested.RemoveAt (i);
580                         }
581
582                         if (nested.Count > 0) {
583                                 var nestedArray = nested.ToArray ();
584                                 Array.Sort (nestedArray, TypeReferenceComparer.Default);
585
586                                 writer.WriteStartElement ("classes");
587                                 foreach (TypeDefinition t in nestedArray) {
588                                         TypeData td = new TypeData (writer, t);
589                                         td.DoOutput ();
590                                 }
591                                 writer.WriteEndElement (); // classes
592                         }
593
594                         writer.WriteEndElement (); // class
595                 }
596
597                 static FieldReference GetEnumValueField (TypeDefinition type)
598                 {
599                         foreach (FieldDefinition field in type.Fields)
600                                 if (field.IsSpecialName && field.Name == "value__")
601                                         return field;
602
603                         return null;
604                 }
605
606                 protected override string GetMemberAttributes (MemberReference member)
607                 {
608                         if (member != type)
609                                 throw new InvalidOperationException ("odd");
610
611                         return ((int) type.Attributes).ToString (CultureInfo.InvariantCulture);
612                 }
613
614                 public static bool MustDocumentMethod (MethodDefinition method) {
615                         // All other methods
616                         MethodAttributes maskedAccess = method.Attributes & MethodAttributes.MemberAccessMask;
617                         return maskedAccess == MethodAttributes.Public
618                                 || maskedAccess == MethodAttributes.Family
619                                 || maskedAccess == MethodAttributes.FamORAssem;
620                 }
621
622                 static string GetClassType (TypeDefinition t)
623                 {
624                         if (t.IsEnum)
625                                 return "enum";
626
627                         if (t.IsValueType)
628                                 return "struct";
629
630                         if (t.IsInterface)
631                                 return "interface";
632
633                         if (TypeHelper.IsDelegate(t))
634                                 return "delegate";
635
636                         if (t.IsPointer)
637                                 return "pointer";
638
639                         return "class";
640                 }
641
642                 static string GetCharSet (TypeDefinition type)
643                 {
644                         TypeAttributes maskedStringFormat = type.Attributes & TypeAttributes.StringFormatMask;
645                         if (maskedStringFormat == TypeAttributes.AnsiClass)
646                                 return CharSet.Ansi.ToString ();
647
648                         if (maskedStringFormat == TypeAttributes.AutoClass)
649                                 return CharSet.Auto.ToString ();
650
651                         if (maskedStringFormat == TypeAttributes.UnicodeClass)
652                                 return CharSet.Unicode.ToString ();
653
654                         return CharSet.None.ToString ();
655                 }
656
657                 static string GetLayout (TypeDefinition type)
658                 {
659                         TypeAttributes maskedLayout = type.Attributes & TypeAttributes.LayoutMask;
660                         if (maskedLayout == TypeAttributes.AutoLayout)
661                                 return LayoutKind.Auto.ToString ();
662
663                         if (maskedLayout == TypeAttributes.ExplicitLayout)
664                                 return LayoutKind.Explicit.ToString ();
665
666                         if (maskedLayout == TypeAttributes.SequentialLayout)
667                                 return LayoutKind.Sequential.ToString ();
668
669                         return null;
670                 }
671
672                 FieldDefinition [] GetFields (TypeDefinition type) {
673                         ArrayList list = new ArrayList ();
674
675                         var fields = type.Fields;
676                         foreach (FieldDefinition field in fields) {
677                                 if (field.IsSpecialName)
678                                         continue;
679
680                                 if (Driver.AbiMode && field.IsStatic)
681                                         continue;
682
683                                 // we're only interested in public or protected members
684                                 FieldAttributes maskedVisibility = (field.Attributes & FieldAttributes.FieldAccessMask);
685                                 if (Driver.AbiMode && !field.IsNotSerialized) {
686                                         list.Add (field);
687                                 } else {
688                                         if (maskedVisibility == FieldAttributes.Public
689                                                 || maskedVisibility == FieldAttributes.Family
690                                                 || maskedVisibility == FieldAttributes.FamORAssem) {
691                                                 list.Add (field);
692                                         }
693                                 }
694                         }
695
696                         return (FieldDefinition []) list.ToArray (typeof (FieldDefinition));
697                 }
698
699
700                 internal static PropertyDefinition [] GetProperties (TypeDefinition type, bool fullAPI) {
701                         var list = new List<PropertyDefinition> ();
702
703                         var t = type;
704                         do {
705                                 var properties = t.Properties;//type.GetProperties (flags);
706                                 foreach (PropertyDefinition property in properties) {
707                                         MethodDefinition getMethod = property.GetMethod;
708                                         MethodDefinition setMethod = property.SetMethod;
709
710                                         bool hasGetter = (getMethod != null) && MustDocumentMethod (getMethod);
711                                         bool hasSetter = (setMethod != null) && MustDocumentMethod (setMethod);
712
713                                         // if neither the getter or setter should be documented, then
714                                         // skip the property
715                                         if (hasGetter || hasSetter) {
716
717                                                 if (t != type && list.Any (l => l.Name == property.Name))
718                                                         continue;
719
720                                                 list.Add (property);
721                                         }
722                                 }
723
724                                 if (!fullAPI)
725                                         break;
726
727                                 if (t.IsInterface || t.IsEnum)
728                                         break;
729
730                                 if (t.BaseType == null || t.BaseType.FullName == "System.Object")
731                                         t = null;
732                                 else
733                                         t = t.BaseType.Resolve ();
734
735                         } while (t != null);
736
737                         return list.ToArray ();
738                 }
739
740                 private MethodDefinition[] GetMethods (TypeDefinition type, bool fullAPI)
741                 {
742                         var list = new List<MethodDefinition> ();
743
744                         var t = type;
745                         do {
746                                 var methods = t.Methods;//type.GetMethods (flags);
747                                 foreach (MethodDefinition method in methods) {
748                                         if (method.IsSpecialName && !method.Name.StartsWith ("op_", StringComparison.Ordinal))
749                                                 continue;
750
751                                         // we're only interested in public or protected members
752                                         if (!MustDocumentMethod (method))
753                                                 continue;
754
755                                         if (t == type && IsFinalizer (method)) {
756                                                 string name = method.DeclaringType.Name;
757                                                 int arity = name.IndexOf ('`');
758                                                 if (arity > 0)
759                                                         name = name.Substring (0, arity);
760
761                                                 method.Name = "~" + name;
762                                         }
763
764                                         if (t != type && list.Any (l => l.DeclaringType != method.DeclaringType && l.Name == method.Name && l.Parameters.Count == method.Parameters.Count &&
765                                                                    l.Parameters.SequenceEqual (method.Parameters, new ParameterComparer ())))
766                                                 continue;
767
768                                         list.Add (method);
769                                 }
770
771                                 if (!fullAPI)
772                                         break;
773
774                                 if (t.IsInterface || t.IsEnum)
775                                         break;
776
777                                 if (t.BaseType == null || t.BaseType.FullName == "System.Object")
778                                         t = null;
779                                 else
780                                         t = t.BaseType.Resolve ();
781
782                         } while (t != null);
783
784                         return list.ToArray ();
785                 }
786
787                 sealed class ParameterComparer : IEqualityComparer<ParameterDefinition>
788                 {
789                         public bool Equals (ParameterDefinition x, ParameterDefinition y)
790                         {
791                                 return x.ParameterType.Name == y.ParameterType.Name;
792                         }
793
794                         public int GetHashCode (ParameterDefinition obj)
795                         {
796                                 return obj.ParameterType.Name.GetHashCode ();
797                         }
798                 }
799
800                 static bool IsFinalizer (MethodDefinition method)
801                 {
802                         if (method.Name != "Finalize")
803                                 return false;
804
805                         if (!method.IsVirtual)
806                                 return false;
807
808                         if (method.Parameters.Count != 0)
809                                 return false;
810
811                         return true;
812                 }
813
814                 private MethodDefinition [] GetConstructors (TypeDefinition type)
815                 {
816                         ArrayList list = new ArrayList ();
817
818                         var ctors = type.Methods.Where (m => m.IsConstructor);//type.GetConstructors (flags);
819                         foreach (MethodDefinition constructor in ctors) {
820                                 // we're only interested in public or protected members
821                                 if (!MustDocumentMethod(constructor))
822                                         continue;
823
824                                 list.Add (constructor);
825                         }
826
827                         return (MethodDefinition []) list.ToArray (typeof (MethodDefinition));
828                 }
829
830                 private EventDefinition[] GetEvents (TypeDefinition type)
831                 {
832                         ArrayList list = new ArrayList ();
833
834                         var events = type.Events;//type.GetEvents (flags);
835                         foreach (EventDefinition eventDef in events) {
836                                 MethodDefinition addMethod = eventDef.AddMethod;//eventInfo.GetAddMethod (true);
837
838                                 if (addMethod == null || !MustDocumentMethod (addMethod))
839                                         continue;
840
841                                 list.Add (eventDef);
842                         }
843
844                         return (EventDefinition []) list.ToArray (typeof (EventDefinition));
845                 }
846         }
847
848         class FieldData : MemberData
849         {
850                 public FieldData (XmlWriter writer, FieldDefinition [] members)
851                         : base (writer, members)
852                 {
853                 }
854
855                 protected override string GetName (MemberReference memberDefenition)
856                 {
857                         FieldDefinition field = (FieldDefinition) memberDefenition;
858                         return field.Name;
859                 }
860
861                 protected override string GetMemberAttributes (MemberReference memberDefenition)
862                 {
863                         FieldDefinition field = (FieldDefinition) memberDefenition;
864                         return ((int) field.Attributes).ToString (CultureInfo.InvariantCulture);
865                 }
866
867                 protected override void AddExtraAttributes (MemberReference memberDefinition)
868                 {
869                         base.AddExtraAttributes (memberDefinition);
870
871                         FieldDefinition field = (FieldDefinition) memberDefinition;
872                         AddAttribute ("fieldtype", Utils.CleanupTypeName (field.FieldType));
873
874                         if (field.IsLiteral) {
875                                 object value = field.Constant;//object value = field.GetValue (null);
876                                 string stringValue = null;
877                                 //if (value is Enum) {
878                                 //    // FIXME: when Mono bug #60090 has been
879                                 //    // fixed, we should just be able to use
880                                 //    // Convert.ToString
881                                 //    stringValue = ((Enum) value).ToString ("D", CultureInfo.InvariantCulture);
882                                 //}
883                                 //else {
884                                 stringValue = Convert.ToString (value, CultureInfo.InvariantCulture);
885                                 //}
886
887                                 if (stringValue != null)
888                                         AddAttribute ("value", stringValue);
889                         }
890                 }
891
892                 public override string ParentTag {
893                         get { return "fields"; }
894                 }
895
896                 public override string Tag {
897                         get { return "field"; }
898                 }
899         }
900
901         class PropertyData : MemberData
902         {
903                 public PropertyData (XmlWriter writer, PropertyDefinition [] members)
904                         : base (writer, members)
905                 {
906                 }
907
908                 protected override string GetName (MemberReference memberDefenition)
909                 {
910                         PropertyDefinition prop = (PropertyDefinition) memberDefenition;
911                         return prop.Name;
912                 }
913
914                 MethodDefinition [] GetMethods (PropertyDefinition prop, out bool haveParameters)
915                 {
916                         MethodDefinition _get = prop.GetMethod;
917                         MethodDefinition _set = prop.SetMethod;
918                         bool haveGet = (_get != null && TypeData.MustDocumentMethod(_get));
919                         bool haveSet = (_set != null && TypeData.MustDocumentMethod(_set));
920                         haveParameters = haveGet || (haveSet && _set.Parameters.Count > 1);
921                         MethodDefinition [] methods;
922
923                         if (haveGet && haveSet) {
924                                 methods = new MethodDefinition [] { _get, _set };
925                         } else if (haveGet) {
926                                 methods = new MethodDefinition [] { _get };
927                         } else if (haveSet) {
928                                 methods = new MethodDefinition [] { _set };
929                         } else {
930                                 //odd
931                                 return null;
932                         }
933
934                         return methods;
935                 }
936
937                 protected override void AddExtraAttributes (MemberReference memberDefinition)
938                 {
939                         base.AddExtraAttributes (memberDefinition);
940
941                         PropertyDefinition prop = (PropertyDefinition) memberDefinition;
942                         AddAttribute ("ptype", Utils.CleanupTypeName (prop.PropertyType));
943
944                         bool haveParameters;
945                         MethodDefinition [] methods = GetMethods ((PropertyDefinition) memberDefinition, out haveParameters);
946
947                         if (methods != null && haveParameters) {
948                                 string parms = Parameters.GetSignature (methods [0].Parameters);
949                                 if (!string.IsNullOrEmpty (parms))
950                                         AddAttribute ("params", parms);
951                         }
952
953                 }
954
955                 protected override void AddExtraData (MemberReference memberDefenition)
956                 {
957                         base.AddExtraData (memberDefenition);
958
959                         bool haveParameters;
960                         MethodDefinition [] methods = GetMethods ((PropertyDefinition) memberDefenition, out haveParameters);
961
962                         if (methods == null)
963                                 return;
964                         
965                         MethodData data = new MethodData (writer, methods);
966                         //data.NoMemberAttributes = true;
967                         data.DoOutput ();
968                 }
969
970                 protected override string GetMemberAttributes (MemberReference memberDefenition)
971                 {
972                         PropertyDefinition prop = (PropertyDefinition) memberDefenition;
973                         return ((int) prop.Attributes).ToString (CultureInfo.InvariantCulture);
974                 }
975
976                 public override string ParentTag {
977                         get { return "properties"; }
978                 }
979
980                 public override string Tag {
981                         get { return "property"; }
982                 }
983         }
984
985         class EventData : MemberData
986         {
987                 public EventData (XmlWriter writer, EventDefinition [] members)
988                         : base (writer, members)
989                 {
990                 }
991
992                 protected override string GetName (MemberReference memberDefenition)
993                 {
994                         EventDefinition evt = (EventDefinition) memberDefenition;
995                         return evt.Name;
996                 }
997
998                 protected override string GetMemberAttributes (MemberReference memberDefenition)
999                 {
1000                         EventDefinition evt = (EventDefinition) memberDefenition;
1001                         return ((int) evt.Attributes).ToString (CultureInfo.InvariantCulture);
1002                 }
1003
1004                 protected override void AddExtraAttributes (MemberReference memberDefinition)
1005                 {
1006                         base.AddExtraAttributes (memberDefinition);
1007
1008                         EventDefinition evt = (EventDefinition) memberDefinition;
1009                         AddAttribute ("eventtype", Utils.CleanupTypeName (evt.EventType));
1010                 }
1011
1012                 public override string ParentTag {
1013                         get { return "events"; }
1014                 }
1015
1016                 public override string Tag {
1017                         get { return "event"; }
1018                 }
1019         }
1020
1021         class MethodData : MemberData
1022         {
1023                 bool noAtts;
1024
1025                 public MethodData (XmlWriter writer, MethodDefinition [] members)
1026                         : base (writer, members)
1027                 {
1028                 }
1029
1030                 protected override string GetName (MemberReference memberDefenition)
1031                 {
1032                         MethodDefinition method = (MethodDefinition) memberDefenition;
1033                         string name = method.Name;
1034                         string parms = Parameters.GetSignature (method.Parameters);
1035
1036                         return string.Format ("{0}({1})", name, parms);
1037                 }
1038
1039                 protected override string GetMemberAttributes (MemberReference memberDefenition)
1040                 {
1041                         MethodDefinition method = (MethodDefinition) memberDefenition;
1042                         return ((int)( method.Attributes)).ToString (CultureInfo.InvariantCulture);
1043                 }
1044
1045                 protected override ICustomAttributeProvider GetAdditionalCustomAttributeProvider (MemberReference member)
1046                 {
1047                         var mbase = (MethodDefinition) member;
1048                         return mbase.MethodReturnType;
1049                 }
1050
1051                 protected override void AddExtraAttributes (MemberReference memberDefinition)
1052                 {
1053                         base.AddExtraAttributes (memberDefinition);
1054
1055                         if (!(memberDefinition is MethodDefinition))
1056                                 return;
1057
1058                         MethodDefinition mbase = (MethodDefinition) memberDefinition;
1059
1060                         if (mbase.IsAbstract)
1061                                 AddAttribute ("abstract", "true");
1062                         if (mbase.IsVirtual)
1063                                 AddAttribute ("virtual", "true");
1064                         if (mbase.IsFinal && mbase.IsVirtual && mbase.IsReuseSlot)
1065                                 AddAttribute ("sealed", "true");
1066                         if (mbase.IsStatic)
1067                                 AddAttribute ("static", "true");
1068                         var baseMethod = TypeHelper.GetBaseMethodInTypeHierarchy (mbase);
1069                         if (baseMethod != null && baseMethod != mbase) {
1070                                 // This indicates whether this method is an override of another method.
1071                                 // This information is not necessarily available in the api info for any
1072                                 // particular assembly, because a method is only overriding another if
1073                                 // there is a base virtual function with the same signature, and that
1074                                 // base method can come from another assembly.
1075                                 AddAttribute ("is-override", "true");
1076                         }
1077                         string rettype = Utils.CleanupTypeName (mbase.MethodReturnType.ReturnType);
1078                         if (rettype != "System.Void" || !mbase.IsConstructor)
1079                                 AddAttribute ("returntype", (rettype));
1080 //
1081 //                      if (mbase.MethodReturnType.HasCustomAttributes)
1082 //                              AttributeData.OutputAttributes (writer, mbase.MethodReturnType);
1083                 }
1084
1085                 protected override void AddExtraData (MemberReference memberDefenition)
1086                 {
1087                         base.AddExtraData (memberDefenition);
1088
1089                         if (!(memberDefenition is MethodDefinition))
1090                                 return;
1091
1092                         MethodDefinition mbase = (MethodDefinition)memberDefenition;
1093
1094                         ParameterData parms = new ParameterData (writer, mbase.Parameters) {
1095                                 HasExtensionParameter = mbase.CustomAttributes.Any (l => l.AttributeType.FullName == "System.Runtime.CompilerServices.ExtensionAttribute")
1096                         };
1097
1098                         parms.DoOutput ();
1099
1100                         MemberData.OutputGenericParameters (writer, mbase);
1101                 }
1102
1103                 public override bool NoMemberAttributes {
1104                         get { return noAtts; }
1105                         set { noAtts = value; }
1106                 }
1107
1108                 public override string ParentTag {
1109                         get { return "methods"; }
1110                 }
1111
1112                 public override string Tag {
1113                         get { return "method"; }
1114                 }
1115         }
1116
1117         class ConstructorData : MethodData
1118         {
1119                 public ConstructorData (XmlWriter writer, MethodDefinition [] members)
1120                         : base (writer, members)
1121                 {
1122                 }
1123
1124                 public override string ParentTag {
1125                         get { return "constructors"; }
1126                 }
1127
1128                 public override string Tag {
1129                         get { return "constructor"; }
1130                 }
1131         }
1132
1133         class ParameterData : BaseData
1134         {
1135                 private IList<ParameterDefinition> parameters;
1136
1137                 public ParameterData (XmlWriter writer, IList<ParameterDefinition> parameters)
1138                         : base (writer)
1139                 {
1140                         this.parameters = parameters;
1141                 }
1142
1143                 public bool HasExtensionParameter { get; set; }
1144
1145                 public override void DoOutput ()
1146                 {
1147                         bool first = true;
1148                         writer.WriteStartElement ("parameters");
1149                         foreach (ParameterDefinition parameter in parameters) {
1150                                 writer.WriteStartElement ("parameter");
1151                                 AddAttribute ("name", parameter.Name);
1152                                 AddAttribute ("position", parameter.Method.Parameters.IndexOf(parameter).ToString(CultureInfo.InvariantCulture));
1153                                 AddAttribute ("attrib", ((int) parameter.Attributes).ToString());
1154
1155                                 string direction = first && HasExtensionParameter ? "this" : "in";
1156                                 first = false;
1157
1158                                 if (parameter.ParameterType is ByReferenceType)
1159                                         direction = parameter.IsOut ? "out" : "ref";
1160
1161                                 TypeReference t = parameter.ParameterType;
1162                                 AddAttribute ("type", Utils.CleanupTypeName (t));
1163
1164                                 if (parameter.IsOptional) {
1165                                         AddAttribute ("optional", "true");
1166                                         if (parameter.HasConstant)
1167                                                 AddAttribute ("defaultValue", parameter.Constant == null ? "NULL" : parameter.Constant.ToString ());
1168                                 }
1169
1170                                 if (direction != "in")
1171                                         AddAttribute ("direction", direction);
1172
1173                                 AttributeData.OutputAttributes (writer, parameter);
1174                                 writer.WriteEndElement (); // parameter
1175                         }
1176                         writer.WriteEndElement (); // parameters
1177                 }
1178         }
1179
1180         class AttributeData
1181         {
1182                 public static void DoOutput (XmlWriter writer, IList<ICustomAttributeProvider> providers)
1183                 {
1184                         if (writer == null)
1185                                 throw new InvalidOperationException ("Document not set");
1186
1187                         if (providers == null || providers.Count == 0)
1188                                 return;
1189                 
1190                         if (!providers.Any ((provider) => provider != null && provider.HasCustomAttributes))
1191                                 return;
1192
1193                         writer.WriteStartElement ("attributes");
1194
1195                         foreach (var provider in providers) {
1196                                 if (provider == null)
1197                                         continue;
1198                                 
1199                                 if (!provider.HasCustomAttributes)
1200                                         continue;
1201
1202
1203                                 var ass = provider as AssemblyDefinition;
1204                                 if (ass != null && !Driver.FollowForwarders)
1205                                         TypeForwardedToData.OutputForwarders (writer, ass);
1206
1207                                 var attributes = provider.CustomAttributes.
1208                                         Where ((att) => !SkipAttribute (att)).
1209                                         OrderBy ((a) => a.Constructor.DeclaringType.FullName, StringComparer.Ordinal);
1210                                 
1211                                 foreach (var att in attributes) {
1212                                         string attName = Utils.CleanupTypeName (att.Constructor.DeclaringType);
1213
1214                                         writer.WriteStartElement ("attribute");
1215                                         writer.WriteAttributeString ("name", attName);
1216
1217                                         var attribute_mapping = CreateAttributeMapping (att);
1218
1219                                         if (attribute_mapping != null) {
1220                                                 var mapping = attribute_mapping.Where ((attr) => attr.Key != "TypeId");
1221                                                 if (mapping.Any ()) {
1222                                                         writer.WriteStartElement ("properties");
1223                                                         foreach (var kvp in mapping) {
1224                                                                 string name = kvp.Key;
1225                                                                 object o = kvp.Value;
1226
1227                                                                 writer.WriteStartElement ("property");
1228                                                                 writer.WriteAttributeString ("name", name);
1229
1230                                                                 if (o == null) {
1231                                                                         writer.WriteAttributeString ("value", "null");
1232                                                                 } else {
1233                                                                         string value = o.ToString ();
1234                                                                         if (attName.EndsWith ("GuidAttribute", StringComparison.Ordinal))
1235                                                                                 value = value.ToUpper ();
1236                                                                         writer.WriteAttributeString ("value", value);
1237                                                                 }
1238
1239                                                                 writer.WriteEndElement (); // property
1240                                                         }
1241                                                         writer.WriteEndElement (); // properties
1242                                                 }
1243                                         }
1244                                         writer.WriteEndElement (); // attribute
1245                                 }
1246                         }
1247
1248                         writer.WriteEndElement (); // attributes
1249                 }
1250
1251                 static Dictionary<string, object> CreateAttributeMapping (CustomAttribute attribute)
1252                 {
1253                         Dictionary<string, object> mapping = null;
1254
1255                         PopulateMapping (ref mapping, attribute);
1256
1257                         var constructor = attribute.Constructor.Resolve ();
1258                         if (constructor == null || !constructor.HasParameters)
1259                                 return mapping;
1260
1261                         PopulateMapping (ref mapping, constructor, attribute);
1262
1263                         return mapping;
1264                 }
1265
1266                 static void PopulateMapping (ref Dictionary<string, object> mapping, CustomAttribute attribute)
1267                 {
1268                         if (!attribute.HasProperties)
1269                                 return;
1270                         
1271                         foreach (var named_argument in attribute.Properties) {
1272                                 var name = named_argument.Name;
1273                                 var arg = named_argument.Argument;
1274
1275                                 if (arg.Value is CustomAttributeArgument)
1276                                         arg = (CustomAttributeArgument) arg.Value;
1277
1278                                 if (mapping == null)
1279                                         mapping = new Dictionary<string, object> (StringComparer.Ordinal);
1280                                 mapping.Add (name, GetArgumentValue (arg.Type, arg.Value));
1281                         }
1282                 }
1283
1284                 static Dictionary<FieldReference, int> CreateArgumentFieldMapping (MethodDefinition constructor)
1285                 {
1286                         Dictionary<FieldReference, int> field_mapping = null;
1287
1288                         int? argument = null;
1289
1290                         foreach (Instruction instruction in constructor.Body.Instructions) {
1291                                 switch (instruction.OpCode.Code) {
1292                                 case Code.Ldarg_1:
1293                                         argument = 1;
1294                                         break;
1295                                 case Code.Ldarg_2:
1296                                         argument = 2;
1297                                         break;
1298                                 case Code.Ldarg_3:
1299                                         argument = 3;
1300                                         break;
1301                                 case Code.Ldarg:
1302                                 case Code.Ldarg_S:
1303                                         argument = ((ParameterDefinition) instruction.Operand).Index + 1;
1304                                         break;
1305
1306                                 case Code.Stfld:
1307                                         FieldReference field = (FieldReference) instruction.Operand;
1308                                         if (field.DeclaringType.FullName != constructor.DeclaringType.FullName)
1309                                                 continue;
1310
1311                                         if (!argument.HasValue)
1312                                                 break;
1313
1314                                         if (field_mapping == null)
1315                                                 field_mapping = new Dictionary<FieldReference, int> ();
1316                                         
1317                                         if (!field_mapping.ContainsKey (field))
1318                                                 field_mapping.Add (field, (int) argument - 1);
1319
1320                                         argument = null;
1321                                         break;
1322                                 }
1323                         }
1324
1325                         return field_mapping;
1326                 }
1327
1328                 static Dictionary<PropertyDefinition, FieldReference> CreatePropertyFieldMapping (TypeDefinition type)
1329                 {
1330                         Dictionary<PropertyDefinition, FieldReference> property_mapping = null;
1331
1332                         foreach (PropertyDefinition property in type.Properties) {
1333                                 if (property.GetMethod == null)
1334                                         continue;
1335                                 if (!property.GetMethod.HasBody)
1336                                         continue;
1337
1338                                 foreach (Instruction instruction in property.GetMethod.Body.Instructions) {
1339                                         if (instruction.OpCode.Code != Code.Ldfld)
1340                                                 continue;
1341
1342                                         FieldReference field = (FieldReference) instruction.Operand;
1343                                         if (field.DeclaringType.FullName != type.FullName)
1344                                                 continue;
1345
1346                                         if (property_mapping == null)
1347                                                 property_mapping = new Dictionary<PropertyDefinition, FieldReference> ();
1348                                         property_mapping.Add (property, field);
1349                                         break;
1350                                 }
1351                         }
1352
1353                         return property_mapping;
1354                 }
1355
1356                 static void PopulateMapping (ref Dictionary<string, object> mapping, MethodDefinition constructor, CustomAttribute attribute)
1357                 {
1358                         if (!constructor.HasBody)
1359                                 return;
1360
1361                         // Custom handling for attributes with arguments which cannot be easily extracted
1362                         var ca = attribute.ConstructorArguments;
1363                         switch (constructor.DeclaringType.FullName) {
1364                         case "System.Runtime.CompilerServices.DecimalConstantAttribute":
1365                                 var dca = constructor.Parameters[2].ParameterType == constructor.Module.TypeSystem.Int32 ?
1366                                         new DecimalConstantAttribute ((byte) ca[0].Value, (byte) ca[1].Value, (int) ca[2].Value, (int) ca[3].Value, (int) ca[4].Value) :
1367                                         new DecimalConstantAttribute ((byte) ca[0].Value, (byte) ca[1].Value, (uint) ca[2].Value, (uint) ca[3].Value, (uint) ca[4].Value);
1368
1369                                 if (mapping == null)
1370                                         mapping = new Dictionary<string, object> (StringComparer.Ordinal);
1371                                 mapping.Add ("Value", dca.Value);
1372                                 return;
1373                         case "System.ComponentModel.BindableAttribute":
1374                                 if (ca.Count != 1)
1375                                         break;
1376
1377                                 if (constructor.Parameters[0].ParameterType == constructor.Module.TypeSystem.Boolean) {
1378                                         if (mapping == null)
1379                                                 mapping = new Dictionary<string, object> (StringComparer.Ordinal);
1380                                         mapping.Add ("Bindable", ca[0].Value);
1381                                 } else {
1382                                         throw new NotImplementedException ();
1383                                 }
1384
1385                                 return;
1386                         }
1387
1388                         var field_mapping = CreateArgumentFieldMapping (constructor);
1389                         if (field_mapping != null) { 
1390                                 var property_mapping = CreatePropertyFieldMapping ((TypeDefinition) constructor.DeclaringType);
1391
1392                                 if (property_mapping != null) {
1393                                         foreach (var pair in property_mapping) {
1394                                                 int argument;
1395                                                 if (!field_mapping.TryGetValue (pair.Value, out argument))
1396                                                         continue;
1397
1398                                                 var ca_arg = ca [argument];
1399                                                 if (ca_arg.Value is CustomAttributeArgument)
1400                                                         ca_arg = (CustomAttributeArgument)ca_arg.Value;
1401
1402                                                 if (mapping == null)
1403                                                         mapping = new Dictionary<string, object> (StringComparer.Ordinal);
1404                                                 mapping.Add (pair.Key.Name, GetArgumentValue (ca_arg.Type, ca_arg.Value));
1405                                         }
1406                                 }
1407                         }
1408                 }
1409
1410                 static object GetArgumentValue (TypeReference reference, object value)
1411                 {
1412                         var type = reference.Resolve ();
1413                         if (type == null)
1414                                 return value;
1415
1416                         if (type.IsEnum) {
1417                                 if (IsFlaggedEnum (type))
1418                                         return GetFlaggedEnumValue (type, value);
1419
1420                                 return GetEnumValue (type, value);
1421                         }
1422
1423                         return value;
1424                 }
1425
1426                 static bool IsFlaggedEnum (TypeDefinition type)
1427                 {
1428                         if (!type.IsEnum)
1429                                 return false;
1430
1431                         if (!type.HasCustomAttributes)
1432                                 return false;
1433
1434                         foreach (CustomAttribute attribute in type.CustomAttributes)
1435                                 if (attribute.Constructor.DeclaringType.FullName == "System.FlagsAttribute")
1436                                         return true;
1437
1438                         return false;
1439                 }
1440
1441                 static object GetFlaggedEnumValue (TypeDefinition type, object value)
1442                 {
1443                         if (value is ulong)
1444                                 return GetFlaggedEnumValue (type, (ulong)value);
1445
1446                         long flags = Convert.ToInt64 (value);
1447                         var signature = new StringBuilder ();
1448
1449                         for (int i = type.Fields.Count - 1; i >= 0; i--) {
1450                                 FieldDefinition field = type.Fields [i];
1451
1452                                 if (!field.HasConstant)
1453                                         continue;
1454
1455                                 long flag = Convert.ToInt64 (field.Constant);
1456
1457                                 if (flag == 0)
1458                                         continue;
1459
1460                                 if ((flags & flag) == flag) {
1461                                         if (signature.Length != 0)
1462                                                 signature.Append (", ");
1463
1464                                         signature.Append (field.Name);
1465                                         flags -= flag;
1466                                 }
1467                         }
1468
1469                         return signature.ToString ();
1470                 }
1471
1472                 static object GetFlaggedEnumValue (TypeDefinition type, ulong flags)
1473                 {
1474                         var signature = new StringBuilder ();
1475
1476                         for (int i = type.Fields.Count - 1; i >= 0; i--) {
1477                                 FieldDefinition field = type.Fields [i];
1478
1479                                 if (!field.HasConstant)
1480                                         continue;
1481
1482                                 ulong flag = Convert.ToUInt64 (field.Constant);
1483
1484                                 if (flag == 0)
1485                                         continue;
1486
1487                                 if ((flags & flag) == flag) {
1488                                         if (signature.Length != 0)
1489                                                 signature.Append (", ");
1490
1491                                         signature.Append (field.Name);
1492                                         flags -= flag;
1493                                 }
1494                         }
1495
1496                         return signature.ToString ();
1497                 }
1498
1499                 static object GetEnumValue (TypeDefinition type, object value)
1500                 {
1501                         foreach (FieldDefinition field in type.Fields) {
1502                                 if (!field.HasConstant)
1503                                         continue;
1504
1505                                 if (Comparer.Default.Compare (field.Constant, value) == 0)
1506                                         return field.Name;
1507                         }
1508
1509                         return value;
1510                 }
1511
1512                 static bool SkipAttribute (CustomAttribute attribute)
1513                 {
1514                         if (!TypeHelper.IsPublic (attribute))
1515                                 return true;
1516                         
1517                         return attribute.Constructor.DeclaringType.Name.EndsWith ("TODOAttribute", StringComparison.Ordinal);
1518                 }
1519
1520                 public static void OutputAttributes (XmlWriter writer, params ICustomAttributeProvider[] providers)
1521                 {
1522                         AttributeData.DoOutput (writer, providers);
1523                 }
1524         }
1525
1526         static class Parameters {
1527
1528                 public static string GetSignature (IList<ParameterDefinition> infos)
1529                 {
1530                         if (infos == null || infos.Count == 0)
1531                                 return string.Empty;
1532
1533                         var signature = new StringBuilder ();
1534                         for (int i = 0; i < infos.Count; i++) {
1535
1536                                 if (i > 0)
1537                                         signature.Append (", ");
1538
1539                                 ParameterDefinition info = infos [i];
1540
1541                                 if (info.ParameterType.IsByReference) {
1542                                         string modifier;
1543                                         if ((info.Attributes & (ParameterAttributes.Out | ParameterAttributes.In)) == ParameterAttributes.Out)
1544                                                 modifier = "out";
1545                                         else
1546                                                 modifier = "ref";
1547
1548                                         signature.Append (modifier);
1549                                         signature.Append (" ");
1550                                 }
1551
1552                                 signature.Append (Utils.CleanupTypeName (info.ParameterType));
1553                         }
1554
1555                         return signature.ToString ();
1556                 }
1557
1558         }
1559
1560         class TypeReferenceComparer : IComparer<TypeReference>
1561         {
1562                 public static TypeReferenceComparer Default = new TypeReferenceComparer ();
1563
1564                 public int Compare (TypeReference a, TypeReference b)
1565                 {
1566                         int result = String.Compare (a.Namespace, b.Namespace, StringComparison.Ordinal);
1567                         if (result != 0)
1568                                 return result;
1569
1570                         return String.Compare (a.Name, b.Name, StringComparison.Ordinal);
1571                 }
1572         }
1573
1574         class MemberReferenceComparer : IComparer
1575         {
1576                 public static MemberReferenceComparer Default = new MemberReferenceComparer ();
1577
1578                 public int Compare (object a, object b)
1579                 {
1580                         MemberReference ma = (MemberReference) a;
1581                         MemberReference mb = (MemberReference) b;
1582                         return String.Compare (ma.Name, mb.Name, StringComparison.Ordinal);
1583                 }
1584         }
1585
1586         class PropertyDefinitionComparer : IComparer<PropertyDefinition>
1587         {
1588                 public static PropertyDefinitionComparer Default = new PropertyDefinitionComparer ();
1589
1590                 public int Compare (PropertyDefinition ma, PropertyDefinition mb)
1591                 {
1592                         int res = String.Compare (ma.Name, mb.Name, StringComparison.Ordinal);
1593                         if (res != 0)
1594                                 return res;
1595
1596                         if (!ma.HasParameters && !mb.HasParameters)
1597                                 return 0;
1598
1599                         if (!ma.HasParameters)
1600                                 return -1;
1601
1602                         if (!mb.HasParameters)
1603                                 return 1;
1604
1605                         return MethodDefinitionComparer.Compare (ma.Parameters, mb.Parameters);
1606                 }
1607         }
1608
1609         class MethodDefinitionComparer : IComparer
1610         {
1611                 public static MethodDefinitionComparer Default = new MethodDefinitionComparer ();
1612
1613                 public int Compare (object a, object b)
1614                 {
1615                         MethodDefinition ma = (MethodDefinition) a;
1616                         MethodDefinition mb = (MethodDefinition) b;
1617                         int res = String.Compare (ma.Name, mb.Name, StringComparison.Ordinal);
1618                         if (res != 0)
1619                                 return res;
1620
1621                         if (!ma.HasParameters && !mb.HasParameters)
1622                                 return 0;
1623
1624                         if (!ma.HasParameters)
1625                                 return -1;
1626
1627                         if (!mb.HasParameters)
1628                                 return 1;
1629
1630                         res = Compare (ma.Parameters, mb.Parameters);
1631                         if (res != 0)
1632                                 return res;
1633
1634                         if (ma.HasGenericParameters != mb.HasGenericParameters)
1635                                 return ma.HasGenericParameters ? -1 : 1;
1636
1637                         if (ma.HasGenericParameters && mb.HasGenericParameters) {
1638                                 res = ma.GenericParameters.Count - mb.GenericParameters.Count;
1639                                 if (res != 0)
1640                                         return res;
1641                         }
1642
1643                         // operators can differ by only return type
1644                         return string.CompareOrdinal (ma.ReturnType.FullName, mb.ReturnType.FullName);
1645                 }
1646
1647                 public static int Compare (IList<ParameterDefinition> pia, IList<ParameterDefinition> pib)
1648                 {
1649                         var res = pia.Count - pib.Count;
1650                         if (res != 0)
1651                                 return res;
1652
1653                         string siga = Parameters.GetSignature (pia);
1654                         string sigb = Parameters.GetSignature (pib);
1655                         return String.Compare (siga, sigb, StringComparison.Ordinal);
1656                 }
1657         }
1658 }
1659