Merge pull request #2247 from ivmai/match-ext-libgc-api
[mono.git] / mcs / tools / mdoc / Mono.Documentation / monodocer.cs
1 // Updater program for syncing Mono's ECMA-style documentation files
2 // with an assembly.
3 // By Joshua Tauberer <tauberer@for.net>
4
5 using System;
6 using System.Collections;
7 using System.Collections.Generic;
8 using System.Collections.ObjectModel;
9 using System.Diagnostics;
10 using System.Globalization;
11 using System.IO;
12 using System.Linq;
13 using System.Text;
14 using System.Xml;
15 using System.Xml.XPath;
16
17 using Mono.Cecil;
18 using Mono.Options;
19
20 using MyXmlNodeList        = System.Collections.Generic.List<System.Xml.XmlNode>;
21 using StringList           = System.Collections.Generic.List<string>;
22 using StringToStringMap    = System.Collections.Generic.Dictionary<string, string>;
23 using StringToXmlNodeMap   = System.Collections.Generic.Dictionary<string, System.Xml.XmlNode>;
24
25 namespace Mono.Documentation {
26         static class NativeTypeManager {
27
28                 static Dictionary<string, string> toNativeType = new Dictionary<string,string>(){
29
30                         {"int", "nint"},
31                         {"Int32", "nint"},
32                         {"System.Int32", "System.nint"},
33                         {"uint", "nuint"},
34                         {"UInt32", "nuint"},
35                         {"System.UInt32", "System.nuint"},
36                         {"float", "nfloat"},
37                         {"Single", "nfloat"},
38                         {"System.Single", "System.nfloat"},
39                         {"SizeF", "CoreGraphics.CGSize"},
40                         {"System.Drawing.SizeF", "CoreGraphics.CGSize"},
41                         {"PointF", "CoreGraphics.CGPoint"},
42                         {"System.Drawing.PointF", "CoreGraphics.CGPoint"},
43                         {"RectangleF", "CoreGraphics.CGRect" },
44                         {"System.Drawing.RectangleF", "CoreGraphics.CGRect"}
45                 };              
46
47                 static Dictionary<string, string> fromNativeType = new Dictionary<string,string>(){
48
49                         {"nint", "int"},
50                         {"System.nint", "System.Int32"},
51                         {"nuint", "uint"},
52                         {"System.nuint", "System.UInt32"},
53                         {"nfloat", "float"},
54                         {"System.nfloat", "System.Single"},
55                         {"CoreGraphics.CGSize", "System.Drawing.SizeF"},
56                         {"CoreGraphics.CGPoint", "System.Drawing.PointF"},
57                         {"CoreGraphics.CGRect", "System.Drawing.RectangleF"},
58                         {"MonoTouch.CoreGraphics.CGSize", "System.Drawing.SizeF"},
59                         {"MonoTouch.CoreGraphics.CGPoint", "System.Drawing.PointF"},
60                         {"MonoTouch.CoreGraphics.CGRect", "System.Drawing.RectangleF"}
61                 };
62
63                 public static string ConvertToNativeType(string typename) {
64                         string nvalue;
65
66                         bool isOut=false;
67                         bool isArray=false;
68                         string valueToCompare = StripToComparableType (typename, ref isOut, ref isArray);
69
70                         if (toNativeType.TryGetValue (valueToCompare, out nvalue)) {
71
72                                 if (isArray) {
73                                         nvalue += "[]";
74                                 }
75                                 if (isOut) {
76                                         nvalue += "&";
77                                 }
78                                 return nvalue;
79                         }
80                         return typename;
81                 }
82                 public static string ConvertFromNativeType(string typename) {
83                         string nvalue;
84
85                         bool isOut=false;
86                         bool isArray=false;
87                         string valueToCompare = StripToComparableType (typename, ref isOut, ref isArray);
88
89                         if (fromNativeType.TryGetValue (valueToCompare, out nvalue)) {
90                                 if (isArray) {
91                                         nvalue += "[]";
92                                 }
93                                 if (isOut) {
94                                         nvalue += "&";
95                                 }
96                                 return nvalue;
97                         }
98                         // it wasn't one of the native types ... just return it
99                         return typename;
100                 }
101
102                 static string StripToComparableType (string typename, ref bool isOut, ref bool isArray)
103                 {
104                         string valueToCompare = typename;
105                         if (typename.EndsWith ("[]")) {
106                                 valueToCompare = typename.Substring (0, typename.Length - 2);
107                                 isArray = true;
108                         }
109                         if (typename.EndsWith ("&")) {
110                                 valueToCompare = typename.Substring (0, typename.Length - 1);
111                                 isOut = true;
112                         }
113                         if (typename.Contains ("<")) {
114                                 // TODO: Need to recursively process generic parameters
115                         }
116                         return valueToCompare;
117                 }
118
119                 public static string GetTranslatedName(TypeReference t) {
120                         string typename = t.FullName;
121
122                         bool isInAssembly = MDocUpdater.IsInAssemblies (t.Module.Name);
123                         if (isInAssembly && !typename.StartsWith ("System") && MDocUpdater.HasDroppedNamespace (t)) {
124                                 string nameWithDropped = string.Format ("{0}.{1}", MDocUpdater.droppedNamespace, typename);
125                                 return nameWithDropped;
126                         }
127                         return typename;
128                 }
129         }
130 class MDocUpdater : MDocCommand
131 {
132         string srcPath;
133         List<AssemblyDefinition> assemblies;
134         readonly DefaultAssemblyResolver assemblyResolver = new DefaultAssemblyResolver();
135         
136         bool multiassembly;
137         bool delete;
138         bool show_exceptions;
139         bool no_assembly_versions, ignore_missing_types;
140         ExceptionLocations? exceptions;
141         
142         internal int additions = 0, deletions = 0;
143
144         List<DocumentationImporter> importers = new List<DocumentationImporter> ();
145
146         DocumentationEnumerator docEnum;
147
148         string since;
149
150         static readonly MemberFormatter docTypeFormatter     = new DocTypeMemberFormatter ();
151         static readonly MemberFormatter filenameFormatter    = new FileNameMemberFormatter ();
152
153         static MemberFormatter[] typeFormatters = new MemberFormatter[]{
154                 new CSharpMemberFormatter (),
155                 new ILMemberFormatter (),
156         };
157
158         static MemberFormatter[] memberFormatters = new MemberFormatter[]{
159                 new CSharpFullMemberFormatter (),
160                 new ILFullMemberFormatter (),
161         };
162
163         internal static readonly MemberFormatter slashdocFormatter    = new SlashDocMemberFormatter ();
164
165         MyXmlNodeList extensionMethods = new MyXmlNodeList ();
166
167         HashSet<string> forwardedTypes = new HashSet<string> ();
168
169         public static string droppedNamespace = string.Empty;
170
171         public static bool HasDroppedNamespace(TypeDefinition forType) 
172         {
173                 return HasDroppedNamespace(forType.Module);
174         }
175
176         public static bool HasDroppedNamespace(MemberReference forMember) 
177         {
178                 return HasDroppedNamespace(forMember.Module);
179         }
180
181         public static bool HasDroppedNamespace(AssemblyDefinition forAssembly) 
182         {
183                 return HasDroppedNamespace(forAssembly.MainModule);
184         }
185
186         public static bool HasDroppedNamespace(ModuleDefinition forModule) 
187         {
188                 return !string.IsNullOrWhiteSpace (droppedNamespace) && droppedAssemblies.Any(da => da == forModule.Name);
189         }
190
191         public static bool HasDroppedAnyNamespace ()
192         {
193                 return !string.IsNullOrWhiteSpace (droppedNamespace);
194         }
195
196         
197         static List<string> droppedAssemblies = new List<string>();
198
199         public string PreserveTag { get; set; }
200         public static MDocUpdater Instance { get; private set; }
201         public static bool SwitchingToMagicTypes { get; private set; }
202
203         public override void Run (IEnumerable<string> args)
204         {
205                 Instance = this;
206                 show_exceptions = DebugOutput;
207                 var types = new List<string> ();
208                 var p = new OptionSet () {
209                         { "delete",
210                                 "Delete removed members from the XML files.",
211                                 v => delete = v != null },
212                         { "exceptions:",
213                           "Document potential exceptions that members can generate.  {SOURCES} " +
214                                 "is a comma-separated list of:\n" +
215                                 "  asm      Method calls in same assembly\n" +
216                                 "  depasm   Method calls in dependent assemblies\n" +
217                                 "  all      Record all possible exceptions\n" +
218                                 "  added    Modifier; only create <exception/>s\n" +
219                                 "             for NEW types/members\n" +
220                                 "If nothing is specified, then only exceptions from the member will " +
221                                 "be listed.",
222                                 v => exceptions = ParseExceptionLocations (v) },
223                         { "f=",
224                                 "Specify a {FLAG} to alter behavior.  See later -f* options for available flags.",
225                                 v => {
226                                         switch (v) {
227                                                 case "ignore-missing-types":
228                                                         ignore_missing_types = true;
229                                                         break;
230                                                 case "no-assembly-versions":
231                                                         no_assembly_versions = true;
232                                                         break;
233                                                 default:
234                                                         throw new Exception ("Unsupported flag `" + v + "'.");
235                                         }
236                                 } },
237                         { "fignore-missing-types",
238                                 "Do not report an error if a --type=TYPE type\nwas not found.",
239                                 v => ignore_missing_types = v != null },
240                         { "fno-assembly-versions",
241                                 "Do not generate //AssemblyVersion elements.",
242                                 v => no_assembly_versions = v != null },
243                         { "i|import=", 
244                                 "Import documentation from {FILE}.",
245                                 v => AddImporter (v) },
246                         { "L|lib=",
247                                 "Check for assembly references in {DIRECTORY}.",
248                                 v => assemblyResolver.AddSearchDirectory (v) },
249                         { "library=",
250                                 "Ignored for compatibility with update-ecma-xml.",
251                                 v => {} },
252                         { "o|out=",
253                                 "Root {DIRECTORY} to generate/update documentation.",
254                                 v => srcPath = v },
255                         { "r=",
256                                 "Search for dependent assemblies in the directory containing {ASSEMBLY}.\n" +
257                                 "(Equivalent to '-L `dirname ASSEMBLY`'.)",
258                                 v => assemblyResolver.AddSearchDirectory (Path.GetDirectoryName (v)) },
259                         { "since=",
260                                 "Manually specify the assembly {VERSION} that new members were added in.",
261                                 v => since = v },
262                         { "type=",
263                           "Only update documentation for {TYPE}.",
264                                 v => types.Add (v) },
265                         { "dropns=",
266                           "When processing assembly {ASSEMBLY}, strip off leading namespace {PREFIX}:\n" +
267                           "  e.g. --dropns ASSEMBLY=PREFIX",
268                           v => {
269                             var parts = v.Split ('=');
270                             if (parts.Length != 2) { Console.Error.WriteLine ("Invalid dropns input"); return; }
271                             var assembly = Path.GetFileName (parts [0].Trim ());
272                             var prefix = parts [1].Trim();
273                             droppedAssemblies.Add (assembly);
274                             droppedNamespace = prefix;
275                         } },
276                         { "ntypes",
277                                 "If the new assembly is switching to 'magic types', then this switch should be defined.",
278                                 v => SwitchingToMagicTypes = true },
279                         { "preserve",
280                                 "Do not delete members that don't exist in the assembly, but rather mark them as preserved.",
281                                 v => PreserveTag = "true" },
282                         { "multiassembly",
283                                 "Allow types to be in multiple assemblies.",
284                                 v => multiassembly = true },
285                 };
286                 var assemblies = Parse (p, args, "update", 
287                                 "[OPTIONS]+ ASSEMBLIES",
288                                 "Create or update documentation from ASSEMBLIES.");
289                 if (assemblies == null)
290                         return;
291                 if (assemblies.Count == 0)
292                         Error ("No assemblies specified.");
293
294                 foreach (var dir in assemblies
295                                 .Where (a => a.Contains (Path.DirectorySeparatorChar))
296                                 .Select (a => Path.GetDirectoryName (a)))
297                         assemblyResolver.AddSearchDirectory (dir);
298
299                 // PARSE BASIC OPTIONS AND LOAD THE ASSEMBLY TO DOCUMENT
300                 
301                 if (srcPath == null)
302                         throw new InvalidOperationException("The --out option is required.");
303                 
304                 this.assemblies = assemblies.Select (a => LoadAssembly (a)).ToList ();
305
306                 // Store types that have been forwarded to avoid duplicate generation
307                 GatherForwardedTypes ();
308
309                 docEnum = docEnum ?? new DocumentationEnumerator ();
310                 
311                 // PERFORM THE UPDATES
312                 
313                 if (types.Count > 0) {
314                         types.Sort ();
315                         DoUpdateTypes (srcPath, types, srcPath);
316                 }
317 #if false
318                 else if (opts.@namespace != null)
319                         DoUpdateNS (opts.@namespace, Path.Combine (opts.path, opts.@namespace),
320                                         Path.Combine (dest_dir, opts.@namespace));
321 #endif
322                 else
323                         DoUpdateAssemblies (srcPath, srcPath);
324
325                 Console.WriteLine("Members Added: {0}, Members Deleted: {1}", additions, deletions);
326         }
327                 public static bool IsInAssemblies(string name) {
328                         var query = Instance.assemblies.Where (a => a.MainModule.Name == name).ToArray ();
329                         return query.Length > 0;
330                 }
331         void AddImporter (string path)
332         {
333                 try {
334                         XmlReader r = new XmlTextReader (path);
335                         if (r.Read ()) {
336                                 while (r.NodeType != XmlNodeType.Element) {
337                                         if (!r.Read ())
338                                                 Error ("Unable to read XML file: {0}.", path);
339                                 }
340                                 if (r.LocalName == "doc") {
341                                         importers.Add (new MsxdocDocumentationImporter (path));
342                                 }
343                                 else if (r.LocalName == "Libraries") {
344                                         var ecmadocs = new XmlTextReader (path);
345                                         docEnum = new EcmaDocumentationEnumerator (this, ecmadocs);
346                                         importers.Add (new EcmaDocumentationImporter (ecmadocs));
347                                 }
348                                 else
349                                         Error ("Unsupported XML format within {0}.", path);
350                         }
351                         r.Close ();
352                 } catch (Exception e) {
353                         Environment.ExitCode = 1;
354                         Error ("Could not load XML file: {0}.", e.Message);
355                 }
356         }
357
358         void GatherForwardedTypes ()
359         {
360                 foreach (var asm in assemblies)
361                         foreach (var type in asm.MainModule.ExportedTypes.Where (t => t.IsForwarder).Select (t => t.FullName))
362                                 forwardedTypes.Add (type);
363         }
364
365         static ExceptionLocations ParseExceptionLocations (string s)
366         {
367                 ExceptionLocations loc = ExceptionLocations.Member;
368                 if (s == null)
369                         return loc;
370                 foreach (var type in s.Split (',')) {
371                         switch (type) {
372                                 case "added":   loc |= ExceptionLocations.AddedMembers; break;
373                                 case "all":     loc |= ExceptionLocations.Assembly | ExceptionLocations.DependentAssemblies; break;
374                                 case "asm":     loc |= ExceptionLocations.Assembly; break;
375                                 case "depasm":  loc |= ExceptionLocations.DependentAssemblies; break;
376                                 default:        throw new NotSupportedException ("Unsupported --exceptions value: " + type);
377                         }
378                 }
379                 return loc;
380         }
381
382         internal void Warning (string format, params object[] args)
383         {
384                 Message (TraceLevel.Warning, "mdoc: " + format, args);
385         }
386         
387         private AssemblyDefinition LoadAssembly (string name)
388         {
389                 AssemblyDefinition assembly = null;
390                 try {
391                         assembly = AssemblyDefinition.ReadAssembly (name, new ReaderParameters { AssemblyResolver = assemblyResolver });
392                 } catch (System.IO.FileNotFoundException) { }
393
394                 if (assembly == null)
395                         throw new InvalidOperationException("Assembly " + name + " not found.");
396
397                 return assembly;
398         }
399
400         private static void WriteXml(XmlElement element, System.IO.TextWriter output) {
401                 OrderTypeAttributes (element);
402                 XmlTextWriter writer = new XmlTextWriter(output);
403                 writer.Formatting = Formatting.Indented;
404                 writer.Indentation = 2;
405                 writer.IndentChar = ' ';
406                 element.WriteTo(writer);
407                 output.WriteLine();     
408         }
409
410         private static void WriteFile (string filename, FileMode mode, Action<TextWriter> action)
411         {
412                 Action<string> creator = file => {
413                         using (var writer = OpenWrite (file, mode))
414                                 action (writer);
415                 };
416
417                 MdocFile.UpdateFile (filename, creator);
418         }
419
420         private static void OrderTypeAttributes (XmlElement e)
421         {
422                 foreach (XmlElement type in e.SelectNodes ("//Type")) {
423                         OrderTypeAttributes (type.Attributes);
424                 }
425         }
426
427         static readonly string[] TypeAttributeOrder = {
428                 "Name", "FullName", "FullNameSP", "Maintainer"
429         };
430
431         private static void OrderTypeAttributes (XmlAttributeCollection c)
432         {
433                 XmlAttribute[] attrs = new XmlAttribute [TypeAttributeOrder.Length];
434                 for (int i = 0; i < c.Count; ++i) {
435                         XmlAttribute a = c [i];
436                         for (int j = 0; j < TypeAttributeOrder.Length; ++j) {
437                                 if (a.Name == TypeAttributeOrder [j]) {
438                                         attrs [j] = a;
439                                         break;
440                                 }
441                         }
442                 }
443                 for (int i = attrs.Length-1; i >= 0; --i) {
444                         XmlAttribute n = attrs [i];
445                         if (n == null)
446                                 continue;
447                         XmlAttribute r = null;
448                         for (int j = i+1; j < attrs.Length; ++j) {
449                                 if (attrs [j] != null) {
450                                         r = attrs [j];
451                                         break;
452                                 }
453                         }
454                         if (r == null)
455                                 continue;
456                         if (c [n.Name] != null) {
457                                 c.RemoveNamedItem (n.Name);
458                                 c.InsertBefore (n, r);
459                         }
460                 }
461         }
462         
463         private XmlDocument CreateIndexStub()
464         {
465                 XmlDocument index = new XmlDocument();
466
467                 XmlElement index_root = index.CreateElement("Overview");
468                 index.AppendChild(index_root);
469
470                 if (assemblies.Count == 0)
471                         throw new Exception ("No assembly");
472
473                 XmlElement index_assemblies = index.CreateElement("Assemblies");
474                 index_root.AppendChild(index_assemblies);
475
476                 XmlElement index_remarks = index.CreateElement("Remarks");
477                 index_remarks.InnerText = "To be added.";
478                 index_root.AppendChild(index_remarks);
479
480                 XmlElement index_copyright = index.CreateElement("Copyright");
481                 index_copyright.InnerText = "To be added.";
482                 index_root.AppendChild(index_copyright);
483
484                 XmlElement index_types = index.CreateElement("Types");
485                 index_root.AppendChild(index_types);
486                 
487                 return index;
488         }
489         
490         private static void WriteNamespaceStub(string ns, string outdir) {
491                 XmlDocument index = new XmlDocument();
492
493                 XmlElement index_root = index.CreateElement("Namespace");
494                 index.AppendChild(index_root);
495                 
496                 index_root.SetAttribute("Name", ns);
497
498                 XmlElement index_docs = index.CreateElement("Docs");
499                 index_root.AppendChild(index_docs);
500
501                 XmlElement index_summary = index.CreateElement("summary");
502                 index_summary.InnerText = "To be added.";
503                 index_docs.AppendChild(index_summary);
504
505                 XmlElement index_remarks = index.CreateElement("remarks");
506                 index_remarks.InnerText = "To be added.";
507                 index_docs.AppendChild(index_remarks);
508
509                 WriteFile (outdir + "/ns-" + ns + ".xml", FileMode.CreateNew, 
510                                 writer => WriteXml (index.DocumentElement, writer));
511         }
512
513         public void DoUpdateTypes (string basepath, List<string> typenames, string dest)
514         {
515                 var index = CreateIndexForTypes (dest);
516
517                 var found = new HashSet<string> ();
518                 foreach (AssemblyDefinition assembly in assemblies) {
519                         foreach (TypeDefinition type in docEnum.GetDocumentationTypes (assembly, typenames)) {
520                                 string relpath = DoUpdateType (type, basepath, dest);
521                                 if (relpath == null)
522                                         continue;
523
524                                 found.Add (type.FullName);
525
526                                 if (index == null)
527                                         continue;
528
529                                 index.Add (assembly);
530                                 index.Add (type);
531                         }
532                 }
533
534                 if (index != null)
535                         index.Write ();
536                 
537                 if (ignore_missing_types)
538                         return;
539
540                 var notFound = from n in typenames where !found.Contains (n) select n;
541                 if (notFound.Any ())
542                         throw new InvalidOperationException("Type(s) not found: " + string.Join (", ", notFound.ToArray ()));
543         }
544
545         class IndexForTypes {
546
547                 MDocUpdater app;
548                 string indexFile;
549
550                 XmlDocument index;
551                 XmlElement index_types;
552                 XmlElement index_assemblies;
553
554                 public IndexForTypes (MDocUpdater app, string indexFile, XmlDocument index)
555                 {
556                         this.app        = app;
557                         this.indexFile  = indexFile;
558                         this.index      = index;
559
560                         index_types = WriteElement (index.DocumentElement, "Types");
561                         index_assemblies = WriteElement (index.DocumentElement, "Assemblies");
562                 }
563
564                 public void Add (AssemblyDefinition assembly)
565                 {
566                         if (index_assemblies.SelectSingleNode ("Assembly[@Name='" + assembly.Name.Name + "']") != null)
567                                 return;
568
569                         app.AddIndexAssembly (assembly, index_assemblies);
570                 }
571
572                 public void Add (TypeDefinition type)
573                 {
574                         app.AddIndexType (type, index_types);
575                 }
576
577                 public void Write ()
578                 {
579                         SortIndexEntries (index_types);
580                         WriteFile (indexFile, FileMode.Create, 
581                                         writer => WriteXml (index.DocumentElement, writer));
582                 }
583         }
584
585         IndexForTypes CreateIndexForTypes (string dest)
586         {
587                 string indexFile = Path.Combine (dest, "index.xml");
588                 if (File.Exists (indexFile))
589                         return null;
590                 return new IndexForTypes (this, indexFile, CreateIndexStub ());
591         }
592
593         /// <summary>Constructs the presumed path to the type's documentation file</summary>
594         /// <returns><c>true</c>, if the type file was found, <c>false</c> otherwise.</returns>
595         /// <param name="result">A typle that contains 1) the 'reltypefile', 2) the 'typefile', and 3) the file info</param>
596         bool TryFindTypeFile(string nsname, string typename, string basepath, out Tuple<string, string, FileInfo> result) {
597                 string reltypefile = DocUtils.PathCombine (nsname, typename + ".xml");
598                 string typefile = Path.Combine (basepath, reltypefile);
599                 System.IO.FileInfo file = new System.IO.FileInfo(typefile);
600
601                 result = new Tuple<string, string, FileInfo> (reltypefile, typefile, file);
602
603                 return file.Exists;
604         }
605         
606         public string DoUpdateType (TypeDefinition type, string basepath, string dest)
607         {
608                 if (type.Namespace == null)
609                         Warning ("warning: The type `{0}' is in the root namespace.  This may cause problems with display within monodoc.",
610                                         type.FullName);
611                 if (!IsPublic (type))
612                         return null;
613                 
614                 // Must get the A+B form of the type name.
615                 string typename = GetTypeFileName(type);
616                 string nsname = DocUtils.GetNamespace (type);
617
618                 // Find the file, if it exists
619                 string[] searchLocations = new string[] {
620                         nsname
621                 };
622
623                 if (MDocUpdater.HasDroppedNamespace (type)) {
624                         // If dropping namespace, types may have moved into a couple of different places.
625                         var newSearchLocations = searchLocations.Union (new string[] {
626                                 string.Format ("{0}.{1}", droppedNamespace, nsname),
627                                 nsname.Replace (droppedNamespace + ".", string.Empty),
628                                 MDocUpdater.droppedNamespace
629                         });
630
631                         searchLocations = newSearchLocations.ToArray ();
632                 }
633
634                 string reltypefile="", typefile="";
635                 System.IO.FileInfo file = null;
636
637                 foreach (var f in searchLocations) {
638                         Tuple<string, string, FileInfo> result;
639                         bool fileExists = TryFindTypeFile (f, typename, basepath, out result);
640
641                         if (fileExists) {
642                                 reltypefile = result.Item1;
643                                 typefile = result.Item2;
644                                 file = result.Item3;
645
646                                 break;
647                         }
648                 }
649
650                 if (file == null || !file.Exists) {
651                         // we were not able to find a file, let's use the original type informatio.
652                         // so that we create the stub in the right place.
653                         Tuple<string, string, FileInfo> result;
654                         TryFindTypeFile (nsname, typename, basepath, out result);
655
656                         reltypefile = result.Item1;
657                         typefile = result.Item2;
658                         file = result.Item3;
659                 }
660                 
661                 string output = null;
662                 if (dest == null) {
663                         output = typefile;
664                 } else if (dest == "-") {
665                         output = null;
666                 } else {
667                         output = Path.Combine (dest, reltypefile);
668                 }       
669
670                 if (file != null && file.Exists) {
671                         // Update
672                         XmlDocument basefile = new XmlDocument();
673                         try {
674                                 basefile.Load(typefile);
675                         } catch (Exception e) {
676                                 throw new InvalidOperationException("Error loading " + typefile + ": " + e.Message, e);
677                         }
678                         
679                         DoUpdateType2("Updating", basefile, type, output, false);
680                 } else {
681                         // Stub
682                         XmlElement td = StubType(type, output);
683                         if (td == null)
684                                 return null;
685                 }
686                 return reltypefile;
687         }
688
689         public void DoUpdateNS (string ns, string nspath, string outpath)
690         {
691                 Dictionary<TypeDefinition, object> seenTypes = new Dictionary<TypeDefinition,object> ();
692                 AssemblyDefinition                  assembly = assemblies [0];
693
694                 foreach (System.IO.FileInfo file in new System.IO.DirectoryInfo(nspath).GetFiles("*.xml")) {
695                         XmlDocument basefile = new XmlDocument();
696                         string typefile = Path.Combine(nspath, file.Name);
697                         try {
698                                 basefile.Load(typefile);
699                         } catch (Exception e) {
700                                 throw new InvalidOperationException("Error loading " + typefile + ": " + e.Message, e);
701                         }
702
703                         string typename = 
704                                 GetTypeFileName (basefile.SelectSingleNode("Type/@FullName").InnerText);
705                         TypeDefinition type = assembly.GetType(typename);
706                         if (type == null) {
707                                         // --
708                                         if (!string.IsNullOrWhiteSpace (droppedNamespace)) {
709                                                 string nameWithNs = string.Format ("{0}.{1}", droppedNamespace, typename);
710                                                 type = assembly.GetType (nameWithNs);
711                                                 if (type == null) {
712                                                         Warning ("Type no longer in assembly: " + typename);
713                                                         continue;
714                                                 }
715                                         }
716                                         //--
717                         }                       
718
719                         seenTypes[type] = seenTypes;
720                         DoUpdateType2("Updating", basefile, type, Path.Combine(outpath, file.Name), false);
721                 }
722                 
723                 // Stub types not in the directory
724                 foreach (TypeDefinition type in docEnum.GetDocumentationTypes (assembly, null)) {
725                         if (type.Namespace != ns || seenTypes.ContainsKey(type))
726                                 continue;
727
728                         XmlElement td = StubType(type, Path.Combine(outpath, GetTypeFileName(type) + ".xml"));
729                         if (td == null) continue;
730                 }
731         }
732         
733         private static string GetTypeFileName (TypeReference type)
734         {
735                 return filenameFormatter.GetName (type);
736         }
737
738         public static string GetTypeFileName (string typename)
739         {
740                 StringBuilder filename = new StringBuilder (typename.Length);
741                 int numArgs = 0;
742                 int numLt = 0;
743                 bool copy = true;
744                 for (int i = 0; i < typename.Length; ++i) {
745                         char c = typename [i];
746                         switch (c) {
747                                 case '<':
748                                         copy = false;
749                                         ++numLt;
750                                         break;
751                                 case '>':
752                                         --numLt;
753                                         if (numLt == 0) {
754                                                 filename.Append ('`').Append ((numArgs+1).ToString());
755                                                 numArgs = 0;
756                                                 copy = true;
757                                         }
758                                         break;
759                                 case ',':
760                                         if (numLt == 1)
761                                                 ++numArgs;
762                                         break;
763                                 default:
764                                         if (copy)
765                                                 filename.Append (c);
766                                         break;
767                         }
768                 }
769                 return filename.ToString ();
770         }
771
772         private void AddIndexAssembly (AssemblyDefinition assembly, XmlElement parent)
773         {
774                 XmlElement index_assembly = null;
775                 if (multiassembly) 
776                         index_assembly = (XmlElement)parent.SelectSingleNode ("Assembly[@Name='"+ assembly.Name.Name +"']");
777                 
778                 if (index_assembly == null) 
779                         index_assembly = parent.OwnerDocument.CreateElement ("Assembly");
780
781                 index_assembly.SetAttribute ("Name", assembly.Name.Name);
782                 index_assembly.SetAttribute ("Version", assembly.Name.Version.ToString());
783
784                 AssemblyNameDefinition name = assembly.Name;
785                 if (name.HasPublicKey) {
786                         XmlElement pubkey = parent.OwnerDocument.CreateElement ("AssemblyPublicKey");
787                         var key = new StringBuilder (name.PublicKey.Length*3 + 2);
788                         key.Append ("[");
789                         foreach (byte b in name.PublicKey)
790                                 key.AppendFormat ("{0,2:x2} ", b);
791                         key.Append ("]");
792                         pubkey.InnerText = key.ToString ();
793                         index_assembly.AppendChild (pubkey);
794                 }
795
796                 if (!string.IsNullOrEmpty (name.Culture)) {
797                         XmlElement culture = parent.OwnerDocument.CreateElement ("AssemblyCulture");
798                         culture.InnerText = name.Culture;
799                         index_assembly.AppendChild (culture);
800                 }
801
802                 MakeAttributes (index_assembly, GetCustomAttributes (assembly.CustomAttributes, ""));
803                 parent.AppendChild(index_assembly);
804         }
805
806         private void AddIndexType (TypeDefinition type, XmlElement index_types)
807         {
808                 string typename = GetTypeFileName(type);
809
810                 // Add namespace and type nodes into the index file as needed
811                 string ns = DocUtils.GetNamespace (type);
812                 XmlElement nsnode = (XmlElement) index_types.SelectSingleNode ("Namespace[@Name='" + ns + "']");
813                 if (nsnode == null) {
814                         nsnode = index_types.OwnerDocument.CreateElement("Namespace");
815                         nsnode.SetAttribute ("Name", ns);
816                         index_types.AppendChild (nsnode);
817                 }
818                 string doc_typename = GetDocTypeName (type);
819                 XmlElement typenode = (XmlElement) nsnode.SelectSingleNode ("Type[@Name='" + typename + "']");
820                 if (typenode == null) {
821                         typenode = index_types.OwnerDocument.CreateElement ("Type");
822                         typenode.SetAttribute ("Name", typename);
823                         nsnode.AppendChild (typenode);
824                 }
825                 if (typename != doc_typename)
826                         typenode.SetAttribute("DisplayName", doc_typename);
827                 else
828                         typenode.RemoveAttribute("DisplayName");
829
830                 typenode.SetAttribute ("Kind", GetTypeKind (type));
831         }
832
833         private void DoUpdateAssemblies (string source, string dest) 
834         {
835                 string indexfile = dest + "/index.xml";
836                 XmlDocument index;
837                 if (System.IO.File.Exists(indexfile)) {
838                         index = new XmlDocument();
839                         index.Load(indexfile);
840
841                         // Format change
842                         ClearElement(index.DocumentElement, "Assembly");
843                         ClearElement(index.DocumentElement, "Attributes");
844                 } else {
845                         index = CreateIndexStub();
846                 }
847                 
848                 string defaultTitle = "Untitled";
849                 if (assemblies.Count == 1)
850                         defaultTitle = assemblies[0].Name.Name;
851                 WriteElementInitialText(index.DocumentElement, "Title", defaultTitle);
852                 
853                 XmlElement index_types = WriteElement(index.DocumentElement, "Types");
854                 XmlElement index_assemblies = WriteElement(index.DocumentElement, "Assemblies");
855                 if (!multiassembly) 
856                         index_assemblies.RemoveAll ();
857
858
859                 HashSet<string> goodfiles = new HashSet<string> (StringComparer.OrdinalIgnoreCase);
860
861                 foreach (AssemblyDefinition assm in assemblies) {
862                         AddIndexAssembly (assm, index_assemblies);
863                         DoUpdateAssembly (assm, index_types, source, dest, goodfiles);
864                 }
865
866                 SortIndexEntries (index_types);
867                 
868                 CleanupFiles (dest, goodfiles);
869                 CleanupIndexTypes (index_types, goodfiles);
870                 CleanupExtensions (index_types);
871
872                 WriteFile (indexfile, FileMode.Create, 
873                                 writer => WriteXml(index.DocumentElement, writer));
874         }
875                 
876         private static char[] InvalidFilenameChars = {'\\', '/', ':', '*', '?', '"', '<', '>', '|'};
877
878         private void DoUpdateAssembly (AssemblyDefinition assembly, XmlElement index_types, string source, string dest, HashSet<string> goodfiles) 
879         {
880                 foreach (TypeDefinition type in docEnum.GetDocumentationTypes (assembly, null)) {
881                         string typename = GetTypeFileName(type);
882                         if (!IsPublic (type) || typename.IndexOfAny (InvalidFilenameChars) >= 0 || forwardedTypes.Contains (type.FullName))
883                                 continue;
884
885                         string reltypepath = DoUpdateType (type, source, dest);
886                         if (reltypepath == null)
887                                 continue;
888                         
889                         // Add namespace and type nodes into the index file as needed
890                         AddIndexType (type, index_types);
891
892                         // Ensure the namespace index file exists
893                         string namespaceToUse = type.Namespace;
894                         if (HasDroppedNamespace(assembly)) {
895                                 namespaceToUse = string.Format ("{0}.{1}", droppedNamespace, namespaceToUse);
896                         }
897                         string onsdoc = DocUtils.PathCombine (dest, namespaceToUse + ".xml");
898                         string nsdoc  = DocUtils.PathCombine (dest, "ns-" + namespaceToUse + ".xml");
899                         if (File.Exists (onsdoc)) {
900                                 File.Move (onsdoc, nsdoc);
901                         }
902
903                         if (!File.Exists (nsdoc)) {
904                                 Console.WriteLine("New Namespace File: " + type.Namespace);
905                                 WriteNamespaceStub(namespaceToUse, dest);
906                         }
907
908                         goodfiles.Add (reltypepath);
909                 }
910         }
911
912         private static void SortIndexEntries (XmlElement indexTypes)
913         {
914                 XmlNodeList namespaces = indexTypes.SelectNodes ("Namespace");
915                 XmlNodeComparer c = new AttributeNameComparer ();
916                 SortXmlNodes (indexTypes, namespaces, c);
917
918                 for (int i = 0; i < namespaces.Count; ++i)
919                         SortXmlNodes (namespaces [i], namespaces [i].SelectNodes ("Type"), c);
920         }
921
922         private static void SortXmlNodes (XmlNode parent, XmlNodeList children, XmlNodeComparer comparer)
923         {
924                 MyXmlNodeList l = new MyXmlNodeList (children.Count);
925                 for (int i = 0; i < children.Count; ++i)
926                         l.Add (children [i]);
927                 l.Sort (comparer);
928                 for (int i = l.Count - 1; i > 0; --i) {
929                         parent.InsertBefore (parent.RemoveChild ((XmlNode) l [i-1]), (XmlNode) l [i]);
930                 }
931         }
932
933         abstract class XmlNodeComparer : IComparer, IComparer<XmlNode>
934         {
935                 public abstract int Compare (XmlNode x, XmlNode y);
936
937                 public int Compare (object x, object y)
938                 {
939                         return Compare ((XmlNode) x, (XmlNode) y);
940                 }
941         }
942
943         class AttributeNameComparer : XmlNodeComparer {
944                 string attribute;
945
946                 public AttributeNameComparer ()
947                         : this ("Name")
948                 {
949                 }
950
951                 public AttributeNameComparer (string attribute)
952                 {
953                         this.attribute = attribute;
954                 }
955
956                 public override int Compare (XmlNode x, XmlNode y)
957                 {
958                         return x.Attributes [attribute].Value.CompareTo (y.Attributes [attribute].Value);
959                 }
960         }
961         
962         class VersionComparer : XmlNodeComparer {
963                 public override int Compare (XmlNode x, XmlNode y)
964                 {
965                         // Some of the existing docs use e.g. 1.0.x.x, which Version doesn't like.
966                         string a = GetVersion (x.InnerText);
967                         string b = GetVersion (y.InnerText);
968                         return new Version (a).CompareTo (new Version (b));
969                 }
970
971                 static string GetVersion (string v)
972                 {
973                         int n = v.IndexOf ("x");
974                         if (n < 0)
975                                 return v;
976                         return v.Substring (0, n-1);
977                 }
978         }
979
980         private static string GetTypeKind (TypeDefinition type)
981         {
982                 if (type.IsEnum)
983                         return "Enumeration";
984                 if (type.IsValueType)
985                         return "Structure";
986                 if (type.IsInterface)
987                         return "Interface";
988                 if (DocUtils.IsDelegate (type))
989                         return "Delegate";
990                 if (type.IsClass || type.FullName == "System.Enum") // FIXME
991                         return "Class";
992                 throw new ArgumentException ("Unknown kind for type: " + type.FullName);
993         }
994
995         public static bool IsPublic (TypeDefinition type)
996         {
997                 TypeDefinition decl = type;
998                 while (decl != null) {
999                         if (!(decl.IsPublic || decl.IsNestedPublic ||
1000                                                 decl.IsNestedFamily || decl.IsNestedFamily || decl.IsNestedFamilyOrAssembly)) {
1001                                 return false;
1002                         }
1003                         decl = (TypeDefinition) decl.DeclaringType;
1004                 }
1005                 return true;
1006         }
1007
1008         private void CleanupFiles (string dest, HashSet<string> goodfiles)
1009         {
1010                 // Look for files that no longer correspond to types
1011                 foreach (System.IO.DirectoryInfo nsdir in new System.IO.DirectoryInfo(dest).GetDirectories("*")) {
1012                         foreach (System.IO.FileInfo typefile in nsdir.GetFiles("*.xml")) {
1013                                 string relTypeFile = Path.Combine(nsdir.Name, typefile.Name);
1014                                 if (!goodfiles.Contains (relTypeFile)) {
1015                                         XmlDocument doc = new XmlDocument ();
1016                                         doc.Load (typefile.FullName);
1017                                         XmlElement e = doc.SelectSingleNode("/Type") as XmlElement;
1018                                         var assemblyNameNode = doc.SelectSingleNode ("/Type/AssemblyInfo/AssemblyName");
1019                                         if (assemblyNameNode == null){
1020                                                 Warning ("Did not find /Type/AssemblyInfo/AssemblyName on {0}", typefile.FullName);
1021                                                 continue;
1022                                         }
1023                                         string assemblyName = assemblyNameNode.InnerText;
1024                                         AssemblyDefinition assembly = assemblies.FirstOrDefault (a => a.Name.Name == assemblyName);
1025
1026                                         Action saveDoc = () => {
1027                                                 using (TextWriter writer = OpenWrite (typefile.FullName, FileMode.Truncate))
1028                                                         WriteXml(doc.DocumentElement, writer);
1029                                         };
1030
1031                                         if (e != null && !no_assembly_versions && assembly != null && assemblyName != null && UpdateAssemblyVersions (e, assembly, GetAssemblyVersions(assemblyName), false)) {
1032                                                 saveDoc ();
1033                                                 goodfiles.Add (relTypeFile);
1034                                                 continue;
1035                                         }
1036
1037                                         Action actuallyDelete = () => {
1038                                                 string newname = typefile.FullName + ".remove";
1039                                                 try { System.IO.File.Delete (newname); } catch (Exception) { Warning ("Unable to delete existing file: {0}", newname); }
1040                                                 try { typefile.MoveTo (newname); } catch (Exception) { Warning ("Unable to rename to: {0}", newname); }
1041                                                 Console.WriteLine ("Class no longer present; file renamed: " + Path.Combine (nsdir.Name, typefile.Name));
1042                                         };
1043
1044                                         if (string.IsNullOrWhiteSpace (PreserveTag)) { // only do this if there was not a -preserve
1045                                                 saveDoc ();
1046
1047                                                 var unifiedAssemblyNode = doc.SelectSingleNode ("/Type/AssemblyInfo[@apistyle='unified']");
1048                                                 var classicAssemblyNode = doc.SelectSingleNode ("/Type/AssemblyInfo[@apistyle='classic']");
1049                                                 var unifiedMembers = doc.SelectNodes ("//Member[@apistyle='unified']|//Member/AssemblyInfo[@apistyle='unified']");
1050                                                 var classicMembers = doc.SelectNodes ("//Member[@apistyle='classic']|//Member/AssemblyInfo[@apistyle='classic']");
1051                                                 bool isUnifiedRun = HasDroppedAnyNamespace ();
1052                                                 bool isClassicOrNormalRun = !isUnifiedRun;
1053
1054                                                 Action<XmlNode, ApiStyle> removeStyles = (x, style) => {
1055                                                         var styledNodes = doc.SelectNodes("//*[@apistyle='"+ style.ToString ().ToLowerInvariant () +"']");
1056                                                         if (styledNodes != null && styledNodes.Count > 0) {
1057                                                                 foreach(var node in styledNodes.Cast<XmlNode> ()) {
1058                                                                         node.ParentNode.RemoveChild (node);
1059                                                                 }
1060                                                         }
1061                                                         saveDoc ();
1062                                                 };
1063                                                 if (isClassicOrNormalRun) {
1064                                                         if (unifiedAssemblyNode != null || unifiedMembers.Count > 0) {
1065                                                                 Warning ("*** this type is marked as unified, not deleting during this run: {0}", typefile.FullName);
1066                                                                 // if truly removed from both assemblies, it will be removed fully during the unified run
1067                                                                 removeStyles (doc, ApiStyle.Classic);
1068                                                                 continue;
1069                                                         } else {
1070                                                                 // we should be safe to delete here because it was not marked as a unified assembly
1071                                                                 actuallyDelete ();
1072                                                         }
1073                                                 }
1074                                                 if (isUnifiedRun) {
1075                                                         if (classicAssemblyNode != null || classicMembers.Count > 0) {
1076                                                                 Warning ("*** this type is marked as classic, not deleting {0}", typefile.FullName);
1077                                                                 continue; 
1078                                                         } else {
1079                                                                 // safe to delete because it wasn't marked as a classic assembly, so the type is gone in both.
1080                                                                 actuallyDelete ();
1081                                                         }
1082                                                 }
1083                                         }
1084                                 }
1085                         }
1086                 }
1087         }
1088
1089         private static TextWriter OpenWrite (string path, FileMode mode)
1090         {
1091                 var w = new StreamWriter (
1092                         new FileStream (path, mode),
1093                         new UTF8Encoding (false)
1094                 );
1095                 w.NewLine = "\n";
1096                 return w;
1097         }
1098
1099         private string[] GetAssemblyVersions (string assemblyName)
1100         {
1101                 return (from a in assemblies 
1102                         where a.Name.Name == assemblyName 
1103                         select GetAssemblyVersion (a)).ToArray ();
1104         }
1105
1106         private static void CleanupIndexTypes (XmlElement index_types, HashSet<string> goodfiles)
1107         {
1108                 // Look for type nodes that no longer correspond to types
1109                 MyXmlNodeList remove = new MyXmlNodeList ();
1110                 foreach (XmlElement typenode in index_types.SelectNodes("Namespace/Type")) {
1111                         string fulltypename = Path.Combine (((XmlElement)typenode.ParentNode).GetAttribute("Name"), typenode.GetAttribute("Name") + ".xml");
1112                         if (!goodfiles.Contains (fulltypename)) {
1113                                 remove.Add (typenode);
1114                         }
1115                 }
1116                 foreach (XmlNode n in remove)
1117                         n.ParentNode.RemoveChild (n);
1118         }
1119
1120         private void CleanupExtensions (XmlElement index_types)
1121         {
1122                 XmlNode e = index_types.SelectSingleNode ("/Overview/ExtensionMethods");
1123                 if (extensionMethods.Count == 0) {
1124                         if (e == null)
1125                                 return;
1126                         index_types.SelectSingleNode ("/Overview").RemoveChild (e);
1127                         return;
1128                 }
1129                 if (e == null) {
1130                         e = index_types.OwnerDocument.CreateElement ("ExtensionMethods");
1131                         index_types.SelectSingleNode ("/Overview").AppendChild (e);
1132                 }
1133                 else
1134                         e.RemoveAll ();
1135                 extensionMethods.Sort (DefaultExtensionMethodComparer);
1136                 foreach (XmlNode m in extensionMethods) {
1137                         e.AppendChild (index_types.OwnerDocument.ImportNode (m, true));
1138                 }
1139         }
1140
1141         class ExtensionMethodComparer : XmlNodeComparer {
1142                 public override int Compare (XmlNode x, XmlNode y)
1143                 {
1144                         XmlNode xLink = x.SelectSingleNode ("Member/Link");
1145                         XmlNode yLink = y.SelectSingleNode ("Member/Link");
1146
1147                         int n = xLink.Attributes ["Type"].Value.CompareTo (
1148                                         yLink.Attributes ["Type"].Value);
1149                         if (n != 0)
1150                                 return n;
1151                         n = xLink.Attributes ["Member"].Value.CompareTo (
1152                                         yLink.Attributes ["Member"].Value);
1153                         if (n == 0 && !object.ReferenceEquals (x, y))
1154                                 throw new InvalidOperationException ("Duplicate extension method found!");
1155                         return n;
1156                 }
1157         }
1158
1159         static readonly XmlNodeComparer DefaultExtensionMethodComparer = new ExtensionMethodComparer ();
1160                 
1161         public void DoUpdateType2 (string message, XmlDocument basefile, TypeDefinition type, string output, bool insertSince)
1162         {
1163                 Console.WriteLine(message + ": " + type.FullName);
1164                 
1165                 StringToXmlNodeMap seenmembers = new StringToXmlNodeMap ();
1166
1167                 // Update type metadata
1168                 UpdateType(basefile.DocumentElement, type);
1169
1170                 // Update existing members.  Delete member nodes that no longer should be there,
1171                 // and remember what members are already documented so we don't add them again.
1172                 
1173                 MyXmlNodeList todelete = new MyXmlNodeList ();
1174                 
1175                 foreach (DocsNodeInfo info in docEnum.GetDocumentationMembers (basefile, type)) {
1176                         XmlElement oldmember  = info.Node;
1177                         MemberReference oldmember2 = info.Member;
1178
1179                         if (info.Member != null &&  info.Node != null) {
1180                                 // Check for an error condition where the xml MemberName doesn't match the matched member
1181                                 var memberName = GetMemberName (info.Member);
1182                                 var memberAttribute = info.Node.Attributes ["MemberName"];
1183                                 if (memberAttribute == null || (memberAttribute.Value != memberName && memberAttribute.Value.Split (',').Length != memberName.Split (',').Length)) {
1184                                         oldmember.SetAttribute ("MemberName", memberName);
1185                                 }
1186                         }
1187
1188                         string sig = oldmember2 != null ? memberFormatters [0].GetDeclaration (oldmember2) : null;
1189                         
1190                         // Interface implementations and overrides are deleted from the docs
1191                         // unless the overrides option is given.
1192                         if (oldmember2 != null && sig == null)
1193                                 oldmember2 = null;
1194                         
1195                         // Deleted (or signature changed)
1196                         if (oldmember2 == null) {
1197                                 if (!no_assembly_versions && UpdateAssemblyVersions (oldmember, type.Module.Assembly, new string[]{ GetAssemblyVersion (type.Module.Assembly) }, false))
1198                                         continue;
1199
1200                                 DeleteMember ("Member Removed", output, oldmember, todelete, type);
1201                                 continue;
1202                         }
1203                         
1204                         // Duplicated
1205                         if (seenmembers.ContainsKey (sig)) {
1206                                 if (object.ReferenceEquals (oldmember, seenmembers [sig])) {
1207                                         // ignore, already seen
1208                                 }
1209                                 else if (DefaultMemberComparer.Compare (oldmember, seenmembers [sig]) == 0)
1210                                         DeleteMember ("Duplicate Member Found", output, oldmember, todelete, type);
1211                                 else
1212                                         Warning ("TODO: found a duplicate member '{0}', but it's not identical to the prior member found!", sig);
1213                                 continue;
1214                         }
1215                         
1216                         // Update signature information
1217                         UpdateMember(info);
1218
1219                         // get all apistyles of sig from info.Node
1220                         var styles = oldmember.GetElementsByTagName ("MemberSignature").Cast<XmlElement> ()
1221                                 .Where (x => x.GetAttribute ("Language") == "C#" && !seenmembers.ContainsKey(x.GetAttribute("Value")))
1222                                 .Select (x => x.GetAttribute ("Value"));
1223
1224                         foreach (var stylesig in styles) {
1225                                 seenmembers.Add (stylesig, oldmember);
1226                         }
1227                 }
1228                 foreach (XmlElement oldmember in todelete)
1229                         oldmember.ParentNode.RemoveChild (oldmember);
1230                 
1231                 
1232                 if (!DocUtils.IsDelegate (type)) {
1233                         XmlNode members = WriteElement (basefile.DocumentElement, "Members");
1234                         var typemembers = type.GetMembers()
1235                                         .Where(m => {
1236                                                 if (m is TypeDefinition) return false;
1237                                                 string sig = memberFormatters [0].GetDeclaration (m);
1238                                                 if (sig == null) return false;
1239                                                 if (seenmembers.ContainsKey(sig)) return false;
1240
1241                                                 // Verify that the member isn't an explicitly implemented 
1242                                                 // member of an internal interface, in which case we shouldn't return true.
1243                                                 MethodDefinition methdef = null;
1244                                                 if (m is MethodDefinition) 
1245                                                         methdef = m as MethodDefinition;
1246                                                 else if (m is PropertyDefinition) {
1247                                                         var prop = m as PropertyDefinition;
1248                                                         methdef = prop.GetMethod ?? prop.SetMethod;
1249                                                 }
1250
1251                                                 if (methdef != null) {
1252                                                         TypeReference iface;
1253                                                         MethodReference imethod;
1254
1255                                                         if (methdef.Overrides.Count == 1) {
1256                                                                 DocUtils.GetInfoForExplicitlyImplementedMethod (methdef, out iface, out imethod);
1257                                                                 if (!IsPublic (iface.Resolve ())) return false;
1258                                                         }
1259                                                 }
1260
1261                                                 return true;
1262                                         })
1263                                         .ToArray();
1264                         foreach (MemberReference m in typemembers) {
1265                                 XmlElement mm = MakeMember(basefile, new DocsNodeInfo (null, m));
1266                                 if (mm == null) continue;
1267
1268                                 if (MDocUpdater.SwitchingToMagicTypes) {
1269                                         // this is a unified style API that obviously doesn't exist in the classic API. Let's mark
1270                                         // it with apistyle="unified", so that it's not displayed for classic style APIs
1271                                         mm.SetAttribute ("apistyle", "unified");
1272                                 }
1273
1274                                 members.AppendChild( mm );
1275         
1276                                 Console.WriteLine("Member Added: " + mm.SelectSingleNode("MemberSignature/@Value").InnerText);
1277                                 additions++;
1278                         }
1279                 }
1280                 
1281                 // Import code snippets from files
1282                 foreach (XmlNode code in basefile.GetElementsByTagName("code")) {
1283                         if (!(code is XmlElement)) continue;
1284                         string file = ((XmlElement)code).GetAttribute("src");
1285                         string lang = ((XmlElement)code).GetAttribute("lang");
1286                         if (file != "") {
1287                                 string src = GetCodeSource (lang, Path.Combine (srcPath, file));
1288                                 if (src != null)
1289                                         code.InnerText = src;
1290                         }
1291                 }
1292
1293                 if (insertSince && since != null) {
1294                         XmlNode docs = basefile.DocumentElement.SelectSingleNode("Docs");
1295                         docs.AppendChild (CreateSinceNode (basefile));
1296                 }
1297
1298                 do {
1299                         XmlElement d = basefile.DocumentElement ["Docs"];
1300                         XmlElement m = basefile.DocumentElement ["Members"];
1301                         if (d != null && m != null)
1302                                 basefile.DocumentElement.InsertBefore (
1303                                                 basefile.DocumentElement.RemoveChild (d), m);
1304                         SortTypeMembers (m);
1305                 } while (false);
1306
1307                 if (output == null)
1308                         WriteXml(basefile.DocumentElement, Console.Out);
1309                 else {
1310                         FileInfo file = new FileInfo (output);
1311                         if (!file.Directory.Exists) {
1312                                 Console.WriteLine("Namespace Directory Created: " + type.Namespace);
1313                                 file.Directory.Create ();
1314                         }
1315                         WriteFile (output, FileMode.Create,
1316                                         writer => WriteXml(basefile.DocumentElement, writer));
1317                 }
1318         }
1319
1320         private string GetCodeSource (string lang, string file)
1321         {
1322                 int anchorStart;
1323                 if (lang == "C#" && (anchorStart = file.IndexOf (".cs#")) >= 0) {
1324                         // Grab the specified region
1325                         string region = "#region " + file.Substring (anchorStart + 4);
1326                         file          = file.Substring (0, anchorStart + 3);
1327                         try {
1328                                 using (StreamReader reader = new StreamReader (file)) {
1329                                         string line;
1330                                         StringBuilder src = new StringBuilder ();
1331                                         int indent = -1;
1332                                         while ((line = reader.ReadLine ()) != null) {
1333                                                 if (line.Trim() == region) {
1334                                                         indent = line.IndexOf (region);
1335                                                         continue;
1336                                                 }
1337                                                 if (indent >= 0 && line.Trim().StartsWith ("#endregion")) {
1338                                                         break;
1339                                                 }
1340                                                 if (indent >= 0)
1341                                                         src.Append (
1342                                                                         (line.Length > 0 ? line.Substring (indent) : string.Empty) +
1343                                                                         "\n");
1344                                         }
1345                                         return src.ToString ();
1346                                 }
1347                         } catch (Exception e) {
1348                                 Warning ("Could not load <code/> file '{0}' region '{1}': {2}",
1349                                                 file, region, show_exceptions ? e.ToString () : e.Message);
1350                                 return null;
1351                         }
1352                 }
1353                 try {
1354                         using (StreamReader reader = new StreamReader (file))
1355                                 return reader.ReadToEnd ();
1356                 } catch (Exception e) {
1357                         Warning ("Could not load <code/> file '" + file + "': " + e.Message);
1358                 }
1359                 return null;
1360         }
1361
1362         void DeleteMember (string reason, string output, XmlNode member, MyXmlNodeList todelete, TypeDefinition type)
1363         {
1364                 string format = output != null
1365                         ? "{0}: File='{1}'; Signature='{4}'"
1366                         : "{0}: XPath='/Type[@FullName=\"{2}\"]/Members/Member[@MemberName=\"{3}\"]'; Signature='{4}'";
1367                 string signature = member.SelectSingleNode ("MemberSignature[@Language='C#']/@Value").Value;
1368                 Warning (format,
1369                                 reason, 
1370                                 output,
1371                                 member.OwnerDocument.DocumentElement.GetAttribute ("FullName"),
1372                                 member.Attributes ["MemberName"].Value, 
1373                                 signature);
1374
1375                 // Identify all of the different states that could affect our decision to delete the member
1376                 bool shouldPreserve = !string.IsNullOrWhiteSpace (PreserveTag);
1377                 bool hasContent = MemberDocsHaveUserContent (member);
1378                 bool shouldDelete = !shouldPreserve && (delete || !hasContent);
1379
1380                 bool unifiedRun = HasDroppedNamespace (type);
1381
1382                 var classicAssemblyInfo = member.SelectSingleNode ("AssemblyInfo[@apistyle='classic']");
1383                 bool nodeIsClassic = classicAssemblyInfo != null || member.HasApiStyle (ApiStyle.Classic);
1384                 var unifiedAssemblyInfo = member.SelectSingleNode ("AssemblyInfo[@apistyle='unified']");
1385                 bool nodeIsUnified = unifiedAssemblyInfo != null || member.HasApiStyle (ApiStyle.Unified);
1386
1387                 Action actuallyDelete = () => {
1388                         todelete.Add (member);
1389                         deletions++;
1390                 };
1391
1392                 if (!shouldDelete) {
1393                         // explicitly not deleting
1394                         string message = shouldPreserve ? 
1395                                         "Not deleting '{0}' due to --preserve." :
1396                                         "Not deleting '{0}'; must be enabled with the --delete option";
1397                         Warning (message, signature);
1398                 } else if (unifiedRun && nodeIsClassic) {
1399                         // this is a unified run, and the member doesn't exist, but is marked as being in the classic assembly.
1400                         member.RemoveApiStyle (ApiStyle.Unified);
1401                         Warning ("Not removing '{0}' since it's still in the classic assembly.", signature);
1402                 } else if (unifiedRun && !nodeIsClassic) {
1403                         // unified run, and the node is not classic, which means it doesn't exist anywhere.
1404                         actuallyDelete ();
1405                 } else { 
1406                         if (!nodeIsClassic && !nodeIsUnified) { // regular codepath (ie. not classic/unified)
1407                                 actuallyDelete ();
1408                         } else { // this is a classic run
1409                                 Warning ("Removing classic from '{0}' ... will be removed in the unified run if not present there.", signature);
1410                                 member.RemoveApiStyle (ApiStyle.Classic);
1411                                 if (classicAssemblyInfo != null) {
1412                                         member.RemoveChild (classicAssemblyInfo);
1413                                 }
1414                         }
1415                 }
1416         }
1417
1418         class MemberComparer : XmlNodeComparer {
1419                 public override int Compare (XmlNode x, XmlNode y)
1420                 {
1421                         int r;
1422                         string xMemberName = x.Attributes ["MemberName"].Value;
1423                         string yMemberName = y.Attributes ["MemberName"].Value;
1424
1425                         // generic methods *end* with '>'
1426                         // it's possible for explicitly implemented generic interfaces to
1427                         // contain <...> without being a generic method
1428                         if ((!xMemberName.EndsWith (">") || !yMemberName.EndsWith (">")) &&
1429                                         (r = xMemberName.CompareTo (yMemberName)) != 0)
1430                                 return r;
1431
1432                         int lt;
1433                         if ((lt = xMemberName.IndexOf ("<")) >= 0)
1434                                 xMemberName = xMemberName.Substring (0, lt);
1435                         if ((lt = yMemberName.IndexOf ("<")) >= 0)
1436                                 yMemberName = yMemberName.Substring (0, lt);
1437                         if ((r = xMemberName.CompareTo (yMemberName)) != 0)
1438                                 return r;
1439
1440                         // if @MemberName matches, then it's either two different types of
1441                         // members sharing the same name, e.g. field & property, or it's an
1442                         // overloaded method.
1443                         // for different type, sort based on MemberType value.
1444                         r = x.SelectSingleNode ("MemberType").InnerText.CompareTo (
1445                                         y.SelectSingleNode ("MemberType").InnerText);
1446                         if (r != 0)
1447                                 return r;
1448
1449                         // same type -- must be an overloaded method.  Sort based on type 
1450                         // parameter count, then parameter count, then by the parameter 
1451                         // type names.
1452                         XmlNodeList xTypeParams = x.SelectNodes ("TypeParameters/TypeParameter");
1453                         XmlNodeList yTypeParams = y.SelectNodes ("TypeParameters/TypeParameter");
1454                         if (xTypeParams.Count != yTypeParams.Count)
1455                                 return xTypeParams.Count <= yTypeParams.Count ? -1 : 1;
1456                         for (int i = 0; i < xTypeParams.Count; ++i) {
1457                                 r = xTypeParams [i].Attributes ["Name"].Value.CompareTo (
1458                                                 yTypeParams [i].Attributes ["Name"].Value);
1459                                 if (r != 0)
1460                                         return r;
1461                         }
1462
1463                         XmlNodeList xParams = x.SelectNodes ("Parameters/Parameter");
1464                         XmlNodeList yParams = y.SelectNodes ("Parameters/Parameter");
1465                         if (xParams.Count != yParams.Count)
1466                                 return xParams.Count <= yParams.Count ? -1 : 1;
1467                         for (int i = 0; i < xParams.Count; ++i) {
1468                                 r = xParams [i].Attributes ["Type"].Value.CompareTo (
1469                                                 yParams [i].Attributes ["Type"].Value);
1470                                 if (r != 0)
1471                                         return r;
1472                         }
1473                         // all parameters match, but return value might not match if it was
1474                         // changed between one version and another.
1475                         XmlNode xReturn = x.SelectSingleNode ("ReturnValue/ReturnType");
1476                         XmlNode yReturn = y.SelectSingleNode ("ReturnValue/ReturnType");
1477                         if (xReturn != null && yReturn != null) {
1478                                 r = xReturn.InnerText.CompareTo (yReturn.InnerText);
1479                                 if (r != 0)
1480                                         return r;
1481                         }
1482
1483                         return 0;
1484                 }
1485         }
1486
1487         static readonly MemberComparer DefaultMemberComparer = new MemberComparer ();
1488
1489         private static void SortTypeMembers (XmlNode members)
1490         {
1491                 if (members == null)
1492                         return;
1493                 SortXmlNodes (members, members.SelectNodes ("Member"), DefaultMemberComparer);
1494         }
1495         
1496         private static bool MemberDocsHaveUserContent (XmlNode e)
1497         {
1498                 e = (XmlElement)e.SelectSingleNode("Docs");
1499                 if (e == null) return false;
1500                 foreach (XmlElement d in e.SelectNodes("*"))
1501                         if (d.InnerText != "" && !d.InnerText.StartsWith("To be added"))
1502                                 return true;
1503                 return false;
1504         }
1505         
1506         // UPDATE HELPER FUNCTIONS
1507         
1508         // CREATE A STUB DOCUMENTATION FILE     
1509
1510         public XmlElement StubType (TypeDefinition type, string output)
1511         {
1512                 string typesig = typeFormatters [0].GetDeclaration (type);
1513                 if (typesig == null) return null; // not publicly visible
1514                 
1515                 XmlDocument doc = new XmlDocument();
1516                 XmlElement root = doc.CreateElement("Type");
1517                 doc.AppendChild (root);
1518
1519                 DoUpdateType2 ("New Type", doc, type, output, true);
1520                 
1521                 return root;
1522         }
1523
1524         private XmlElement CreateSinceNode (XmlDocument doc)
1525         {
1526                 XmlElement s = doc.CreateElement ("since");
1527                 s.SetAttribute ("version", since);
1528                 return s;
1529         }
1530         
1531         // STUBBING/UPDATING FUNCTIONS
1532         
1533         public void UpdateType (XmlElement root, TypeDefinition type)
1534         {
1535                 root.SetAttribute("Name", GetDocTypeName (type));
1536                 root.SetAttribute("FullName", GetDocTypeFullName (type));
1537
1538                 foreach (MemberFormatter f in typeFormatters) {
1539                         string element = "TypeSignature[@Language='" + f.Language + "']";
1540                         string valueToUse = f.GetDeclaration (type);
1541
1542                         AddXmlNode (
1543                                 root.SelectNodes (element).Cast<XmlElement> ().ToArray (), 
1544                                 x => x.GetAttribute ("Value") == valueToUse, 
1545                                 x => x.SetAttribute ("Value", valueToUse), 
1546                                 () => {
1547                                         var node = WriteElementAttribute (root, element, "Language", f.Language, forceNewElement: true);
1548                                         var newnode = WriteElementAttribute (root, node, "Value", valueToUse);
1549                                         return newnode;
1550                                 },
1551                                 type);
1552                 }
1553                 
1554                 AddAssemblyNameToNode (root, type);
1555
1556                 string assemblyInfoNodeFilter = MDocUpdater.HasDroppedNamespace (type) ? "[@apistyle='unified']" : "[not(@apistyle) or @apistyle='classic']";
1557                 Func<XmlElement, bool> assemblyFilter = x => x.SelectSingleNode ("AssemblyName").InnerText == type.Module.Assembly.Name.Name;
1558                 foreach(var ass in root.SelectNodes ("AssemblyInfo" + assemblyInfoNodeFilter).Cast<XmlElement> ().Where (assemblyFilter))
1559                 {
1560                         WriteElementText(ass, "AssemblyName", type.Module.Assembly.Name.Name);
1561                         if (!no_assembly_versions) {
1562                                 UpdateAssemblyVersions (ass, type, true);
1563                         }
1564                         else {
1565                                 var versions = ass.SelectNodes ("AssemblyVersion").Cast<XmlNode> ().ToList ();
1566                                 foreach (var version in versions)
1567                                         ass.RemoveChild (version);
1568                         }
1569                         if (!string.IsNullOrEmpty (type.Module.Assembly.Name.Culture))
1570                                 WriteElementText(ass, "AssemblyCulture", type.Module.Assembly.Name.Culture);
1571                         else
1572                                 ClearElement(ass, "AssemblyCulture");
1573
1574
1575                         // Why-oh-why do we put assembly attributes in each type file?
1576                         // Neither monodoc nor monodocs2html use them, so I'm deleting them
1577                         // since they're outdated in current docs, and a waste of space.
1578                         //MakeAttributes(ass, type.Assembly, true);
1579                         XmlNode assattrs = ass.SelectSingleNode("Attributes");
1580                         if (assattrs != null)
1581                                 ass.RemoveChild(assattrs);
1582
1583                         NormalizeWhitespace(ass);
1584                 }
1585                 
1586                 if (type.IsGenericType ()) {
1587                                 MakeTypeParameters (root, type.GenericParameters, type, MDocUpdater.HasDroppedNamespace(type));
1588                 } else {
1589                         ClearElement(root, "TypeParameters");
1590                 }
1591                 
1592                 if (type.BaseType != null) {
1593                         XmlElement basenode = WriteElement(root, "Base");
1594                         
1595                         string basetypename = GetDocTypeFullName (type.BaseType);
1596                         if (basetypename == "System.MulticastDelegate") basetypename = "System.Delegate";
1597                         WriteElementText(root, "Base/BaseTypeName", basetypename);
1598                         
1599                         // Document how this type instantiates the generic parameters of its base type
1600                         TypeReference origBase = type.BaseType.GetElementType ();
1601                         if (origBase.IsGenericType ()) {
1602                                 ClearElement(basenode, "BaseTypeArguments");
1603                                 GenericInstanceType baseInst             = type.BaseType as GenericInstanceType;
1604                                 IList<TypeReference> baseGenArgs    = baseInst == null ? null : baseInst.GenericArguments;
1605                                 IList<GenericParameter> baseGenParams = origBase.GenericParameters;
1606                                 if (baseGenArgs.Count != baseGenParams.Count)
1607                                         throw new InvalidOperationException ("internal error: number of generic arguments doesn't match number of generic parameters.");
1608                                 for (int i = 0; baseGenArgs != null && i < baseGenArgs.Count; i++) {
1609                                         GenericParameter param = baseGenParams [i];
1610                                         TypeReference    value = baseGenArgs [i];
1611
1612                                         XmlElement bta = WriteElement(basenode, "BaseTypeArguments");
1613                                         XmlElement arg = bta.OwnerDocument.CreateElement("BaseTypeArgument");
1614                                         bta.AppendChild(arg);
1615                                         arg.SetAttribute ("TypeParamName", param.Name);
1616                                         arg.InnerText = GetDocTypeFullName (value);
1617                                 }
1618                         }
1619                 } else {
1620                         ClearElement(root, "Base");
1621                 }
1622
1623                 if (!DocUtils.IsDelegate (type) && !type.IsEnum) {
1624                         IEnumerable<TypeReference> userInterfaces = DocUtils.GetUserImplementedInterfaces (type);
1625                         List<string> interface_names = userInterfaces
1626                                         .Select (iface => GetDocTypeFullName (iface))
1627                                         .OrderBy (s => s)
1628                                         .ToList ();
1629
1630                         XmlElement interfaces = WriteElement(root, "Interfaces");
1631                         interfaces.RemoveAll();
1632                         foreach (string iname in interface_names) {
1633                                 XmlElement iface = root.OwnerDocument.CreateElement("Interface");
1634                                 interfaces.AppendChild(iface);
1635                                 WriteElementText(iface, "InterfaceName", iname);
1636                         }
1637                 } else {
1638                         ClearElement(root, "Interfaces");
1639                 }
1640
1641                         MakeAttributes (root, GetCustomAttributes (type), type);
1642                 
1643                 if (DocUtils.IsDelegate (type)) {
1644                         MakeTypeParameters (root, type.GenericParameters, type, MDocUpdater.HasDroppedNamespace(type));
1645                         var member = type.GetMethod ("Invoke");
1646                         MakeParameters(root, member, member.Parameters);
1647                         MakeReturnValue(root, member);
1648                 }
1649                 
1650                 DocsNodeInfo typeInfo = new DocsNodeInfo (WriteElement(root, "Docs"), type);
1651                 MakeDocNode (typeInfo);
1652                 
1653                 if (!DocUtils.IsDelegate (type))
1654                         WriteElement (root, "Members");
1655
1656                 OrderTypeNodes (root, root.ChildNodes);
1657                 NormalizeWhitespace(root);
1658         }
1659
1660         /// <summary>Adds an AssemblyInfo with AssemblyName node to an XmlElement.</summary>
1661         /// <returns>The assembly that was either added, or was already present</returns>
1662         static XmlElement AddAssemblyNameToNode (XmlElement root, TypeDefinition type)
1663         {
1664                 return AddAssemblyNameToNode (root, type.Module);
1665         }
1666
1667         /// <summary>Adds an AssemblyInfo with AssemblyName node to an XmlElement.</summary>
1668         /// <returns>The assembly that was either added, or was already present</returns>
1669         static XmlElement AddAssemblyNameToNode (XmlElement root, ModuleDefinition module)
1670         {
1671                 Func<XmlElement, bool> assemblyFilter = x => {
1672                         var existingName = x.SelectSingleNode ("AssemblyName");
1673                         return existingName != null && existingName.InnerText == module.Assembly.Name.Name;
1674                 };
1675                 
1676                 return AddAssemblyXmlNode (
1677                         root.SelectNodes ("AssemblyInfo").Cast<XmlElement> ().ToArray (), 
1678                         assemblyFilter, x => WriteElementText (x, "AssemblyName", module.Assembly.Name.Name), 
1679                         () =>  {
1680                                 XmlElement ass = WriteElement (root, "AssemblyInfo", forceNewElement: true);
1681                                 if (MDocUpdater.HasDroppedNamespace (module))
1682                                         ass.SetAttribute ("apistyle", "unified");
1683                                 return ass;
1684                         }, module);
1685         }
1686
1687         static readonly string[] TypeNodeOrder = {
1688                 "TypeSignature",
1689                 "MemberOfLibrary",
1690                 "AssemblyInfo",
1691                 "ThreadingSafetyStatement",
1692                 "ThreadSafetyStatement",
1693                 "TypeParameters",
1694                 "Base",
1695                 "Interfaces",
1696                 "Attributes",
1697                 "Parameters",
1698                 "ReturnValue",
1699                 "Docs",
1700                 "Members",
1701                 "TypeExcluded",
1702         };
1703
1704         static void OrderTypeNodes (XmlNode member, XmlNodeList children)
1705         {
1706                 ReorderNodes (member, children, TypeNodeOrder);
1707         }
1708
1709         internal static IEnumerable<T> Sort<T> (IEnumerable<T> list)
1710         {
1711                 List<T> l = new List<T> (list);
1712                 l.Sort ();
1713                 return l;
1714         }
1715
1716         private void UpdateMember (DocsNodeInfo info)
1717         {
1718                 XmlElement me = (XmlElement) info.Node;
1719                 MemberReference mi = info.Member;
1720
1721                 foreach (MemberFormatter f in memberFormatters) {
1722                         string element = "MemberSignature[@Language='" + f.Language + "']";
1723
1724                         var valueToUse = f.GetDeclaration (mi);
1725
1726                         AddXmlNode (
1727                                 me.SelectNodes (element).Cast<XmlElement> ().ToArray(), 
1728                                 x => x.GetAttribute("Value") == valueToUse, 
1729                                 x => x.SetAttribute ("Value", valueToUse), 
1730                                 () => {
1731                                         var node = WriteElementAttribute (me, element, "Language", f.Language, forceNewElement:true);
1732                                         var newNode = WriteElementAttribute (me, node, "Value", valueToUse);
1733                                         return newNode;
1734                                 },
1735                                 mi);
1736
1737                 }
1738
1739                 WriteElementText(me, "MemberType", GetMemberType(mi));
1740
1741                 if (!no_assembly_versions) {
1742                         if (!multiassembly)
1743                                 UpdateAssemblyVersions (me, mi, true);
1744                         else {
1745                                 var node = AddAssemblyNameToNode (me, mi.Module);
1746
1747                                 UpdateAssemblyVersionForAssemblyInfo (node, me, new[] { GetAssemblyVersion (mi.Module.Assembly) }, add: true);
1748                         }
1749                 }
1750                 else {
1751                         ClearElement (me, "AssemblyInfo");
1752                 }
1753
1754                 MakeAttributes (me, GetCustomAttributes (mi), mi.DeclaringType);
1755
1756                 MakeReturnValue(me, mi, MDocUpdater.HasDroppedNamespace(mi));
1757                 if (mi is MethodReference) {
1758                         MethodReference mb = (MethodReference) mi;
1759                         if (mb.IsGenericMethod ())
1760                                         MakeTypeParameters (me, mb.GenericParameters, mi, MDocUpdater.HasDroppedNamespace(mi));
1761                 }
1762                 MakeParameters(me, mi, MDocUpdater.HasDroppedNamespace(mi));
1763                 
1764                 string fieldValue;
1765                 if (mi is FieldDefinition && GetFieldConstValue ((FieldDefinition)mi, out fieldValue))
1766                         WriteElementText(me, "MemberValue", fieldValue);
1767                 
1768                 info.Node = WriteElement (me, "Docs");
1769                 MakeDocNode (info);
1770                 OrderMemberNodes (me, me.ChildNodes);
1771                 UpdateExtensionMethods (me, info);
1772         }
1773
1774         static void AddXmlNode (XmlElement[] relevant, Func<XmlElement, bool> valueMatches, Action<XmlElement> setValue, Func<XmlElement> makeNewNode, MemberReference member) {
1775                 AddXmlNode (relevant, valueMatches, setValue, makeNewNode, member.Module);
1776         }
1777
1778         static void AddXmlNode (XmlElement[] relevant, Func<XmlElement, bool> valueMatches, Action<XmlElement> setValue, Func<XmlElement> makeNewNode, TypeDefinition type) {
1779                 AddXmlNode (relevant, valueMatches, setValue, makeNewNode, type.Module);
1780         }
1781
1782         static XmlElement AddAssemblyXmlNode (XmlElement[] relevant, Func<XmlElement, bool> valueMatches, Action<XmlElement> setValue, Func<XmlElement> makeNewNode, ModuleDefinition module)
1783         {
1784                 bool isUnified = MDocUpdater.HasDroppedNamespace (module);
1785                 XmlElement thisAssemblyNode = relevant.FirstOrDefault (valueMatches);
1786                 if (thisAssemblyNode == null) {
1787                         thisAssemblyNode = makeNewNode ();
1788                         setValue (thisAssemblyNode);
1789                 }
1790
1791                 if (isUnified) {
1792                         thisAssemblyNode.AddApiStyle (ApiStyle.Unified);
1793
1794                         foreach (var otherNodes in relevant.Where (n => n != thisAssemblyNode && n.DoesNotHaveApiStyle (ApiStyle.Unified))) {
1795                                 otherNodes.AddApiStyle (ApiStyle.Classic);
1796                         }
1797                 }
1798                 return thisAssemblyNode;
1799         }
1800
1801         /// <summary>Adds an xml node, reusing the node if it's available</summary>
1802         /// <param name="relevant">The existing set of nodes</param>
1803         /// <param name="valueMatches">Checks to see if the node's value matches what you're trying to write.</param>
1804         /// <param name="setValue">Sets the node's value</param>
1805         /// <param name="makeNewNode">Creates a new node, if valueMatches returns false.</param>
1806         static void AddXmlNode (XmlElement[] relevant, Func<XmlElement, bool> valueMatches, Action<XmlElement> setValue, Func<XmlElement> makeNewNode, ModuleDefinition module)
1807         {
1808                 bool shouldDuplicate = MDocUpdater.HasDroppedNamespace (module);
1809                 var styleToUse = shouldDuplicate ? ApiStyle.Unified : ApiStyle.Classic;
1810                 var existing = relevant;
1811                 bool done = false;
1812                 bool addedOldApiStyle = false;
1813
1814                 if (shouldDuplicate) {
1815                         existing = existing.Where (n => n.HasApiStyle (styleToUse)).ToArray ();
1816                         foreach (var n in relevant.Where (n => n.DoesNotHaveApiStyle (styleToUse))) {
1817                                 if (valueMatches (n)) {
1818                                         done = true;
1819                                 }
1820                                 else {
1821                                         n.AddApiStyle (ApiStyle.Classic);
1822                                         addedOldApiStyle = true;
1823                                 }
1824                         }
1825                 }
1826                 if (!done) {
1827                         if (!existing.Any ()) {
1828                                 var newNode = makeNewNode ();
1829                                 if (shouldDuplicate && addedOldApiStyle) {
1830                                         newNode.AddApiStyle (ApiStyle.Unified);
1831                                 }
1832                         }
1833                         else {
1834                                 var itemToReuse = existing.First ();
1835                                 setValue (itemToReuse);
1836                                 
1837                                 if (shouldDuplicate && addedOldApiStyle) {
1838                                         itemToReuse.AddApiStyle (styleToUse);
1839                                 }
1840                         }
1841                 }
1842         }
1843
1844         static readonly string[] MemberNodeOrder = {
1845                 "MemberSignature",
1846                 "MemberType",
1847                 "AssemblyInfo",
1848                 "Attributes",
1849                 "ReturnValue",
1850                 "TypeParameters",
1851                 "Parameters",
1852                 "MemberValue",
1853                 "Docs",
1854                 "Excluded",
1855                 "ExcludedLibrary",
1856                 "Link",
1857         };
1858
1859         static void OrderMemberNodes (XmlNode member, XmlNodeList children)
1860         {
1861                 ReorderNodes (member, children, MemberNodeOrder);
1862         }
1863
1864         static void ReorderNodes (XmlNode node, XmlNodeList children, string[] ordering)
1865         {
1866                 MyXmlNodeList newChildren = new MyXmlNodeList (children.Count);
1867                 for (int i = 0; i < ordering.Length; ++i) {
1868                         for (int j = 0; j < children.Count; ++j) {
1869                                 XmlNode c = children [j];
1870                                 if (c.Name == ordering [i]) {
1871                                         newChildren.Add (c);
1872                                 }
1873                         }
1874                 }
1875                 if (newChildren.Count >= 0)
1876                         node.PrependChild ((XmlNode) newChildren [0]);
1877                 for (int i = 1; i < newChildren.Count; ++i) {
1878                         XmlNode prev = (XmlNode) newChildren [i-1];
1879                         XmlNode cur  = (XmlNode) newChildren [i];
1880                         node.RemoveChild (cur);
1881                         node.InsertAfter (cur, prev);
1882                 }
1883         }
1884
1885         IEnumerable<string> GetCustomAttributes (MemberReference mi)
1886         {
1887                 IEnumerable<string> attrs = Enumerable.Empty<string>();
1888
1889                 ICustomAttributeProvider p = mi as ICustomAttributeProvider;
1890                 if (p != null)
1891                         attrs = attrs.Concat (GetCustomAttributes (p.CustomAttributes, ""));
1892
1893                 PropertyDefinition pd = mi as PropertyDefinition;
1894                 if (pd != null) {
1895                         if (pd.GetMethod != null)
1896                                 attrs = attrs.Concat (GetCustomAttributes (pd.GetMethod.CustomAttributes, "get: "));
1897                         if (pd.SetMethod != null)
1898                                 attrs = attrs.Concat (GetCustomAttributes (pd.SetMethod.CustomAttributes, "set: "));
1899                 }
1900
1901                 EventDefinition ed = mi as EventDefinition;
1902                 if (ed != null) {
1903                         if (ed.AddMethod != null)
1904                                 attrs = attrs.Concat (GetCustomAttributes (ed.AddMethod.CustomAttributes, "add: "));
1905                         if (ed.RemoveMethod != null)
1906                                 attrs = attrs.Concat (GetCustomAttributes (ed.RemoveMethod.CustomAttributes, "remove: "));
1907                 }
1908
1909                 return attrs;
1910         }
1911
1912         IEnumerable<string> GetCustomAttributes (IList<CustomAttribute> attributes, string prefix)
1913         {
1914                 foreach (CustomAttribute attribute in attributes.OrderBy (ca => ca.AttributeType.FullName)) {
1915
1916                         TypeDefinition attrType = attribute.AttributeType as TypeDefinition;
1917                         if (attrType != null && !IsPublic (attrType))
1918                                 continue;
1919                         if (slashdocFormatter.GetName (attribute.AttributeType) == null)
1920                                 continue;
1921                         
1922                         if (Array.IndexOf (IgnorableAttributes, attribute.AttributeType.FullName) >= 0)
1923                                 continue;
1924                         
1925                         StringList fields = new StringList ();
1926
1927                         for (int i = 0; i < attribute.ConstructorArguments.Count; ++i) {
1928                                 CustomAttributeArgument argument = attribute.ConstructorArguments [i];
1929                                 fields.Add (MakeAttributesValueString (
1930                                                 argument.Value,
1931                                                 argument.Type));
1932                         }
1933                         var namedArgs =
1934                                 (from namedArg in attribute.Fields
1935                                  select new { Type=namedArg.Argument.Type, Name=namedArg.Name, Value=namedArg.Argument.Value })
1936                                 .Concat (
1937                                                 (from namedArg in attribute.Properties
1938                                                  select new { Type=namedArg.Argument.Type, Name=namedArg.Name, Value=namedArg.Argument.Value }))
1939                                 .OrderBy (v => v.Name);
1940                         foreach (var d in namedArgs)
1941                                 fields.Add (string.Format ("{0}={1}", d.Name, 
1942                                                 MakeAttributesValueString (d.Value, d.Type)));
1943
1944                         string a2 = String.Join(", ", fields.ToArray ());
1945                         if (a2 != "") a2 = "(" + a2 + ")";
1946
1947                         string name = attribute.GetDeclaringType();
1948                         if (name.EndsWith("Attribute")) name = name.Substring(0, name.Length-"Attribute".Length);
1949                         yield return prefix + name + a2;
1950                 }
1951         }
1952
1953         static readonly string[] ValidExtensionMembers = {
1954                 "Docs",
1955                 "MemberSignature",
1956                 "MemberType",
1957                 "Parameters",
1958                 "ReturnValue",
1959                 "TypeParameters",
1960         };
1961
1962         static readonly string[] ValidExtensionDocMembers = {
1963                 "param",
1964                 "summary",
1965                 "typeparam",
1966         };
1967
1968         private void UpdateExtensionMethods (XmlElement e, DocsNodeInfo info)
1969         {
1970                 MethodDefinition me = info.Member as MethodDefinition;
1971                 if (me == null)
1972                         return;
1973                 if (info.Parameters.Count < 1)
1974                         return;
1975                 if (!DocUtils.IsExtensionMethod (me))
1976                         return;
1977
1978                 XmlNode em = e.OwnerDocument.CreateElement ("ExtensionMethod");
1979                 XmlNode member = e.CloneNode (true);
1980                 em.AppendChild (member);
1981                 RemoveExcept (member, ValidExtensionMembers);
1982                 RemoveExcept (member.SelectSingleNode ("Docs"), ValidExtensionDocMembers);
1983                 WriteElementText (member, "MemberType", "ExtensionMethod");
1984                 XmlElement link = member.OwnerDocument.CreateElement ("Link");
1985                 link.SetAttribute ("Type", slashdocFormatter.GetName (me.DeclaringType));
1986                 link.SetAttribute ("Member", slashdocFormatter.GetDeclaration (me));
1987                 member.AppendChild (link);
1988                 AddTargets (em, info);
1989
1990                 extensionMethods.Add (em);
1991         }
1992
1993         private static void RemoveExcept (XmlNode node, string[] except)
1994         {
1995                 if (node == null)
1996                         return;
1997                 MyXmlNodeList remove = null;
1998                 foreach (XmlNode n in node.ChildNodes) {
1999                         if (Array.BinarySearch (except, n.Name) < 0) {
2000                                 if (remove == null)
2001                                         remove = new MyXmlNodeList ();
2002                                 remove.Add (n);
2003                         }
2004                 }
2005                 if (remove != null)
2006                         foreach (XmlNode n in remove)
2007                                 node.RemoveChild (n);
2008         }
2009
2010         private static void AddTargets (XmlNode member, DocsNodeInfo info)
2011         {
2012                 XmlElement targets = member.OwnerDocument.CreateElement ("Targets");
2013                 member.PrependChild (targets);
2014                 if (!(info.Parameters [0].ParameterType is GenericParameter)) {
2015                         AppendElementAttributeText (targets, "Target", "Type",
2016                                 slashdocFormatter.GetDeclaration (info.Parameters [0].ParameterType));
2017                 }
2018                 else {
2019                         GenericParameter gp = (GenericParameter) info.Parameters [0].ParameterType;
2020                         IList<TypeReference> constraints = gp.Constraints;
2021                         if (constraints.Count == 0)
2022                                 AppendElementAttributeText (targets, "Target", "Type", "System.Object");
2023                         else
2024                                 foreach (TypeReference c in constraints)
2025                                         AppendElementAttributeText(targets, "Target", "Type",
2026                                                 slashdocFormatter.GetDeclaration (c));
2027                 }
2028         }
2029         
2030         private static bool GetFieldConstValue (FieldDefinition field, out string value)
2031         {
2032                 value = null;
2033                 TypeDefinition type = field.DeclaringType.Resolve ();
2034                 if (type != null && type.IsEnum) return false;
2035                 
2036                 if (type != null && type.IsGenericType ()) return false;
2037                 if (!field.HasConstant)
2038                         return false;
2039                 if (field.IsLiteral) {
2040                         object val = field.Constant;
2041                         if (val == null) value = "null";
2042                         else if (val is Enum) value = val.ToString();
2043                         else if (val is IFormattable) {
2044                                 value = ((IFormattable)val).ToString();
2045                                 if (val is string)
2046                                         value = "\"" + value + "\"";
2047                         }
2048                         if (value != null && value != "")
2049                                 return true;
2050                 }
2051                 return false;
2052         }
2053         
2054         // XML HELPER FUNCTIONS
2055         
2056         internal static XmlElement WriteElement(XmlNode parent, string element, bool forceNewElement = false) {
2057                 XmlElement ret = (XmlElement)parent.SelectSingleNode(element);
2058                 if (ret == null || forceNewElement) {
2059                         string[] path = element.Split('/');
2060                         foreach (string p in path) {
2061                                 ret = (XmlElement)parent.SelectSingleNode(p);
2062                                 if (ret == null || forceNewElement) {
2063                                         string ename = p;
2064                                         if (ename.IndexOf('[') >= 0) // strip off XPath predicate
2065                                                 ename = ename.Substring(0, ename.IndexOf('['));
2066                                         ret = parent.OwnerDocument.CreateElement(ename);
2067                                         parent.AppendChild(ret);
2068                                         parent = ret;
2069                                 } else {
2070                                         parent = ret;
2071                                 }
2072                         }
2073                 }
2074                 return ret;
2075         }
2076         private static XmlElement WriteElementText(XmlNode parent, string element, string value, bool forceNewElement = false) {
2077                 XmlElement node = WriteElement(parent, element, forceNewElement: forceNewElement);
2078                 node.InnerText = value;
2079                 return node;
2080         }
2081
2082         static XmlElement AppendElementText (XmlNode parent, string element, string value)
2083         {
2084                 XmlElement n = parent.OwnerDocument.CreateElement (element);
2085                 parent.AppendChild (n);
2086                 n.InnerText = value;
2087                 return n;
2088         }
2089
2090         static XmlElement AppendElementAttributeText (XmlNode parent, string element, string attribute, string value)
2091         {
2092                 XmlElement n = parent.OwnerDocument.CreateElement (element);
2093                 parent.AppendChild (n);
2094                 n.SetAttribute (attribute, value);
2095                 return n;
2096         }
2097
2098         internal static XmlNode CopyNode (XmlNode source, XmlNode dest)
2099         {
2100                 XmlNode copy = dest.OwnerDocument.ImportNode (source, true);
2101                 dest.AppendChild (copy);
2102                 return copy;
2103         }
2104
2105         private static void WriteElementInitialText(XmlElement parent, string element, string value) {
2106                 XmlElement node = (XmlElement)parent.SelectSingleNode(element);
2107                 if (node != null)
2108                         return;
2109                 node = WriteElement(parent, element);
2110                 node.InnerText = value;
2111         }
2112         private static XmlElement WriteElementAttribute(XmlElement parent, string element, string attribute, string value, bool forceNewElement = false) {
2113                 XmlElement node = WriteElement(parent, element, forceNewElement:forceNewElement);
2114                 return WriteElementAttribute (parent, node, attribute, value);
2115         }
2116         private static XmlElement WriteElementAttribute(XmlElement parent, XmlElement node, string attribute, string value) {
2117                 if (node.GetAttribute (attribute) != value) {
2118                         node.SetAttribute (attribute, value);
2119                 }
2120                 return node;
2121         }
2122         internal static void ClearElement(XmlElement parent, string name) {
2123                 XmlElement node = (XmlElement)parent.SelectSingleNode(name);
2124                 if (node != null)
2125                         parent.RemoveChild(node);
2126         }
2127         
2128         // DOCUMENTATION HELPER FUNCTIONS
2129         
2130         private void MakeDocNode (DocsNodeInfo info)
2131         {
2132                 List<GenericParameter> genericParams      = info.GenericParameters;
2133                 IList<ParameterDefinition> parameters  = info.Parameters;
2134                 TypeReference returntype                  = info.ReturnType;
2135                 bool returnisreturn         = info.ReturnIsReturn;
2136                 XmlElement e                = info.Node;
2137                 bool addremarks             = info.AddRemarks;
2138
2139                 WriteElementInitialText(e, "summary", "To be added.");
2140                 
2141                 if (parameters != null) {
2142                         string[] values = new string [parameters.Count];
2143                         for (int i = 0; i < values.Length; ++i)
2144                                 values [i] = parameters [i].Name;
2145                         UpdateParameters (e, "param", values);
2146                 }
2147
2148                 if (genericParams != null) {
2149                         string[] values = new string [genericParams.Count];
2150                         for (int i = 0; i < values.Length; ++i)
2151                                 values [i] = genericParams [i].Name;
2152                         UpdateParameters (e, "typeparam", values);
2153                 }
2154
2155                 string retnodename = null;
2156                 if (returntype != null && returntype.FullName != "System.Void") { // FIXME
2157                         retnodename = returnisreturn ? "returns" : "value";
2158                         string retnodename_other = !returnisreturn ? "returns" : "value";
2159                         
2160                         // If it has a returns node instead of a value node, change its name.
2161                         XmlElement retother = (XmlElement)e.SelectSingleNode(retnodename_other);
2162                         if (retother != null) {
2163                                 XmlElement retnode = e.OwnerDocument.CreateElement(retnodename);
2164                                 foreach (XmlNode node in retother)
2165                                         retnode.AppendChild(node.CloneNode(true));
2166                                 e.ReplaceChild(retnode, retother);
2167                         } else {
2168                                 WriteElementInitialText(e, retnodename, "To be added.");
2169                         }
2170                 } else {
2171                         ClearElement(e, "returns");
2172                         ClearElement(e, "value");
2173                 }
2174
2175                 if (addremarks)
2176                         WriteElementInitialText(e, "remarks", "To be added.");
2177
2178                 if (exceptions.HasValue && info.Member != null &&
2179                                 (exceptions.Value & ExceptionLocations.AddedMembers) == 0) {
2180                         UpdateExceptions (e, info.Member);
2181                 }
2182
2183                 foreach (DocumentationImporter importer in importers)
2184                         importer.ImportDocumentation (info);
2185                 
2186                 OrderDocsNodes (e, e.ChildNodes);
2187                 NormalizeWhitespace(e);
2188         }
2189
2190         static readonly string[] DocsNodeOrder = {
2191                 "typeparam", "param", "summary", "returns", "value", "remarks",
2192         };
2193
2194         private static void OrderDocsNodes (XmlNode docs, XmlNodeList children)
2195         {
2196                 ReorderNodes (docs, children, DocsNodeOrder);
2197         }
2198         
2199
2200         private void UpdateParameters (XmlElement e, string element, string[] values)
2201         {       
2202                 if (values != null) {
2203                         XmlNode[] paramnodes = new XmlNode[values.Length];
2204                         
2205                         // Some documentation had param nodes with leading spaces.
2206                         foreach (XmlElement paramnode in e.SelectNodes(element)){
2207                                 paramnode.SetAttribute("name", paramnode.GetAttribute("name").Trim());
2208                         }
2209                         
2210                         // If a member has only one parameter, we can track changes to
2211                         // the name of the parameter easily.
2212                         if (values.Length == 1 && e.SelectNodes(element).Count == 1) {
2213                                 UpdateParameterName (e, (XmlElement) e.SelectSingleNode(element), values [0]);
2214                         }
2215
2216                         bool reinsert = false;
2217
2218                         // Pick out existing and still-valid param nodes, and
2219                         // create nodes for parameters not in the file.
2220                         Hashtable seenParams = new Hashtable();
2221                         for (int pi = 0; pi < values.Length; pi++) {
2222                                 string p = values [pi];
2223                                 seenParams[p] = pi;
2224                                 
2225                                 paramnodes[pi] = e.SelectSingleNode(element + "[@name='" + p + "']");
2226                                 if (paramnodes[pi] != null) continue;
2227                                 
2228                                 XmlElement pe = e.OwnerDocument.CreateElement(element);
2229                                 pe.SetAttribute("name", p);
2230                                 pe.InnerText = "To be added.";
2231                                 paramnodes[pi] = pe;
2232                                 reinsert = true;
2233                         }
2234
2235                         // Remove parameters that no longer exist and check all params are in the right order.
2236                         int idx = 0;
2237                         MyXmlNodeList todelete = new MyXmlNodeList ();
2238                         foreach (XmlElement paramnode in e.SelectNodes(element)) {
2239                                 string name = paramnode.GetAttribute("name");
2240                                 if (!seenParams.ContainsKey(name)) {
2241                                         if (!delete && !paramnode.InnerText.StartsWith("To be added")) {
2242                                                 Warning ("The following param node can only be deleted if the --delete option is given: ");
2243                                                 if (e.ParentNode == e.OwnerDocument.DocumentElement) {
2244                                                         // delegate type
2245                                                         Warning ("\tXPath=/Type[@FullName=\"{0}\"]/Docs/param[@name=\"{1}\"]",
2246                                                                         e.OwnerDocument.DocumentElement.GetAttribute ("FullName"),
2247                                                                         name);
2248                                                 }
2249                                                 else {
2250                                                         Warning ("\tXPath=/Type[@FullName=\"{0}\"]//Member[@MemberName=\"{1}\"]/Docs/param[@name=\"{2}\"]",
2251                                                                         e.OwnerDocument.DocumentElement.GetAttribute ("FullName"),
2252                                                                         e.ParentNode.Attributes ["MemberName"].Value, 
2253                                                                         name);
2254                                                 }
2255                                                 Warning ("\tValue={0}", paramnode.OuterXml);
2256                                         } else {
2257                                                 todelete.Add (paramnode);
2258                                         }
2259                                         continue;
2260                                 }
2261
2262                                 if ((int)seenParams[name] != idx)
2263                                         reinsert = true;
2264                                 
2265                                 idx++;
2266                         }
2267
2268                         foreach (XmlNode n in todelete) {
2269                                 n.ParentNode.RemoveChild (n);
2270                         }
2271                         
2272                         // Re-insert the parameter nodes at the top of the doc section.
2273                         if (reinsert)
2274                                 for (int pi = values.Length-1; pi >= 0; pi--)
2275                                         e.PrependChild(paramnodes[pi]);
2276                 } else {
2277                         // Clear all existing param nodes
2278                         foreach (XmlNode paramnode in e.SelectNodes(element)) {
2279                                 if (!delete && !paramnode.InnerText.StartsWith("To be added")) {
2280                                         Console.WriteLine("The following param node can only be deleted if the --delete option is given:");
2281                                         Console.WriteLine(paramnode.OuterXml);
2282                                 } else {
2283                                         paramnode.ParentNode.RemoveChild(paramnode);
2284                                 }
2285                         }
2286                 }
2287         }
2288
2289         private static void UpdateParameterName (XmlElement docs, XmlElement pe, string newName)
2290         {
2291                 string existingName = pe.GetAttribute ("name");
2292                 pe.SetAttribute ("name", newName);
2293                 if (existingName == newName)
2294                         return;
2295                 foreach (XmlElement paramref in docs.SelectNodes (".//paramref"))
2296                         if (paramref.GetAttribute ("name").Trim () == existingName)
2297                                 paramref.SetAttribute ("name", newName);
2298         }
2299
2300         class CrefComparer : XmlNodeComparer {
2301
2302                 public CrefComparer ()
2303                 {
2304                 }
2305
2306                 public override int Compare (XmlNode x, XmlNode y)
2307                 {
2308                         string xType = x.Attributes ["cref"].Value;
2309                         string yType = y.Attributes ["cref"].Value;
2310                         string xNamespace = GetNamespace (xType);
2311                         string yNamespace = GetNamespace (yType);
2312
2313                         int c = xNamespace.CompareTo (yNamespace);
2314                         if (c != 0)
2315                                 return c;
2316                         return xType.CompareTo (yType);
2317                 }
2318
2319                 static string GetNamespace (string type)
2320                 {
2321                         int n = type.LastIndexOf ('.');
2322                         if (n >= 0)
2323                                 return type.Substring (0, n);
2324                         return string.Empty;
2325                 }
2326         }
2327         
2328         private void UpdateExceptions (XmlNode docs, MemberReference member)
2329         {
2330                 string indent = new string (' ', 10);
2331                 foreach (var source in new ExceptionLookup (exceptions.Value)[member]) {
2332                         string cref = slashdocFormatter.GetDeclaration (source.Exception);
2333                         var node = docs.SelectSingleNode ("exception[@cref='" + cref + "']");
2334                         if (node != null)
2335                                 continue;
2336                         XmlElement e = docs.OwnerDocument.CreateElement ("exception");
2337                         e.SetAttribute ("cref", cref);
2338                         e.InnerXml = "To be added; from:\n" + indent + "<see cref=\"" +
2339                                 string.Join ("\" />,\n" + indent + "<see cref=\"",
2340                                                 source.Sources.Select (m => slashdocFormatter.GetDeclaration (m))
2341                                                 .OrderBy (s => s)) +
2342                                 "\" />";
2343                         docs.AppendChild (e);
2344                 }
2345                 SortXmlNodes (docs, docs.SelectNodes ("exception"), 
2346                                 new CrefComparer ());
2347         }
2348
2349         private static void NormalizeWhitespace(XmlElement e) {
2350                 // Remove all text and whitespace nodes from the element so it
2351                 // is outputted with nice indentation and no blank lines.
2352                 ArrayList deleteNodes = new ArrayList();
2353                 foreach (XmlNode n in e)
2354                         if (n is XmlText || n is XmlWhitespace || n is XmlSignificantWhitespace)
2355                                 deleteNodes.Add(n);
2356                 foreach (XmlNode n in deleteNodes)
2357                                 n.ParentNode.RemoveChild(n);
2358         }
2359         
2360         private static bool UpdateAssemblyVersions (XmlElement root, MemberReference member, bool add)
2361         {
2362                 TypeDefinition type = member as TypeDefinition;
2363                 if (type == null)
2364                         type = member.DeclaringType as TypeDefinition;
2365
2366                 var versions = new string[] { GetAssemblyVersion (type.Module.Assembly) };
2367
2368                 if (root.LocalName == "AssemblyInfo")
2369                         return UpdateAssemblyVersionForAssemblyInfo (root, root.ParentNode as XmlElement, versions, add: true);
2370                 else 
2371                         return UpdateAssemblyVersions (root, type.Module.Assembly, versions, add);
2372         }
2373         
2374         private static string GetAssemblyVersion (AssemblyDefinition assembly)
2375         {
2376                 return assembly.Name.Version.ToString();
2377         }
2378         
2379         private static bool UpdateAssemblyVersions(XmlElement root, AssemblyDefinition assembly, string[] assemblyVersions, bool add)
2380         {
2381                 XmlElement av = (XmlElement) root.SelectSingleNode ("AssemblyVersions");
2382                 if (av != null) {
2383                                 // AssemblyVersions is not part of the spec
2384                                 root.RemoveChild (av);
2385                 }
2386
2387                 string oldNodeFilter = "AssemblyInfo[not(@apistyle) or @apistyle='classic']";
2388                 string newNodeFilter = "AssemblyInfo[@apistyle='unified']";
2389                 string thisNodeFilter = MDocUpdater.HasDroppedNamespace (assembly) ? newNodeFilter : oldNodeFilter;
2390                 string thatNodeFilter = MDocUpdater.HasDroppedNamespace (assembly) ? oldNodeFilter : newNodeFilter;
2391
2392                 XmlElement e = (XmlElement) root.SelectSingleNode (thisNodeFilter);
2393                 if (e == null) {
2394                         e = root.OwnerDocument.CreateElement("AssemblyInfo");
2395
2396                         if (MDocUpdater.HasDroppedNamespace (assembly)) {
2397                                 e.SetAttribute ("apistyle", "unified");
2398                         }
2399
2400                         root.AppendChild(e);
2401                 }
2402
2403                 var thatNode = (XmlElement) root.SelectSingleNode (thatNodeFilter);
2404                 if (MDocUpdater.HasDroppedNamespace (assembly) && thatNode != null) {
2405                         // there's a classic node, we should add apistyles
2406                         e.SetAttribute ("apistyle", "unified");
2407                         thatNode.SetAttribute ("apistyle", "classic");
2408                 }
2409
2410                 return UpdateAssemblyVersionForAssemblyInfo (e, root, assemblyVersions, add);
2411         }
2412
2413         static bool UpdateAssemblyVersionForAssemblyInfo (XmlElement e, XmlElement root, string[] assemblyVersions, bool add)
2414         {
2415                 List<XmlNode> matches = e.SelectNodes ("AssemblyVersion").Cast<XmlNode> ().Where (v => Array.IndexOf (assemblyVersions, v.InnerText) >= 0).ToList ();
2416                 // matches.Count > 0 && add: ignore -- already present
2417                 if (matches.Count > 0 && !add) {
2418                         foreach (XmlNode c in matches)
2419                                 e.RemoveChild (c);
2420                 }
2421                 else if (matches.Count == 0 && add) {
2422                         foreach (string sv in assemblyVersions) {
2423                                 XmlElement c = root.OwnerDocument.CreateElement("AssemblyVersion");
2424                                 c.InnerText = sv;
2425                                 e.AppendChild(c);
2426                         }
2427                 }
2428
2429                 // matches.Count == 0 && !add: ignore -- already not present
2430                 XmlNodeList avs = e.SelectNodes ("AssemblyVersion");
2431                 SortXmlNodes (e, avs, new VersionComparer ());
2432
2433                 bool anyNodesLeft = avs.Count != 0;
2434                 if (!anyNodesLeft) {
2435                         e.ParentNode.RemoveChild (e);
2436                 }
2437                 return anyNodesLeft;
2438         }
2439
2440         // FIXME: get TypeReferences instead of string comparison?
2441         private static string[] IgnorableAttributes = {
2442                 // Security related attributes
2443                 "System.Reflection.AssemblyKeyFileAttribute",
2444                 "System.Reflection.AssemblyDelaySignAttribute",
2445                 // Present in @RefType
2446                 "System.Runtime.InteropServices.OutAttribute",
2447                 // For naming the indexer to use when not using indexers
2448                 "System.Reflection.DefaultMemberAttribute",
2449                 // for decimal constants
2450                 "System.Runtime.CompilerServices.DecimalConstantAttribute",
2451                 // compiler generated code
2452                 "System.Runtime.CompilerServices.CompilerGeneratedAttribute",
2453                 // more compiler generated code, e.g. iterator methods
2454                 "System.Diagnostics.DebuggerHiddenAttribute",
2455                 "System.Runtime.CompilerServices.FixedBufferAttribute",
2456                 "System.Runtime.CompilerServices.UnsafeValueTypeAttribute",
2457                 // extension methods
2458                 "System.Runtime.CompilerServices.ExtensionAttribute",
2459                 // Used to differentiate 'object' from C#4 'dynamic'
2460                 "System.Runtime.CompilerServices.DynamicAttribute",
2461         };
2462
2463         private void MakeAttributes (XmlElement root, IEnumerable<string> attributes, TypeReference t=null)
2464         {
2465                 if (!attributes.Any ()) {
2466                         ClearElement (root, "Attributes");
2467                         return;
2468                 }
2469
2470                 XmlElement e = (XmlElement)root.SelectSingleNode("Attributes");
2471                 if (e != null)
2472                         e.RemoveAll();
2473                 else if (e == null)
2474                         e = root.OwnerDocument.CreateElement("Attributes");
2475                 
2476                 foreach (string attribute in attributes) {
2477                         XmlElement ae = root.OwnerDocument.CreateElement("Attribute");
2478                         e.AppendChild(ae);
2479                         
2480                         WriteElementText(ae, "AttributeName", attribute);
2481                 }
2482                 
2483                 if (e.ParentNode == null)
2484                         root.AppendChild(e);
2485
2486                 NormalizeWhitespace(e);
2487         }
2488
2489         public static string MakeAttributesValueString (object v, TypeReference valueType)
2490         {
2491                 var formatters = new [] { 
2492                         new AttributeValueFormatter (), 
2493                         new ApplePlatformEnumFormatter (), 
2494                         new StandardFlagsEnumFormatter (), 
2495                         new DefaultAttributeValueFormatter (),
2496                 };
2497
2498                 ResolvedTypeInfo type = new ResolvedTypeInfo (valueType);
2499                 foreach (var formatter in formatters) {
2500                         string formattedValue;
2501                         if (formatter.TryFormatValue (v, type, out formattedValue)) {
2502                                 return formattedValue;
2503                         }
2504                 }
2505
2506                 // this should never occur because the DefaultAttributeValueFormatter will always
2507                 // successfully format the value ... but this is needed to satisfy the compiler :)
2508                 throw new InvalidDataException (string.Format ("Unable to format attribute value ({0})", v.ToString ()));
2509         }
2510
2511         internal static IDictionary<long, string> GetEnumerationValues (TypeDefinition type)
2512         {
2513                 var values = new Dictionary<long, string> ();
2514                 foreach (var f in 
2515                                 (from f in type.Fields
2516                                  where !(f.IsRuntimeSpecialName || f.IsSpecialName)
2517                                  select f)) {
2518                         values [ToInt64 (f.Constant)] = f.Name;
2519                 }
2520                 return values;
2521         }
2522
2523         internal static long ToInt64 (object value)
2524         {
2525                 if (value is ulong)
2526                         return (long) (ulong) value;
2527                 return Convert.ToInt64 (value);
2528         }
2529         
2530         private void MakeParameters (XmlElement root, MemberReference member, IList<ParameterDefinition> parameters, bool shouldDuplicateWithNew=false)
2531         {
2532                 XmlElement e = WriteElement(root, "Parameters");
2533
2534                 int i = 0;
2535                 foreach (ParameterDefinition p in parameters) {
2536                         XmlElement pe;
2537                         
2538                         // param info
2539                         var ptype = GetDocParameterType (p.ParameterType);
2540                         var newPType = ptype;
2541
2542                         if (MDocUpdater.SwitchingToMagicTypes) {
2543                                 newPType = NativeTypeManager.ConvertFromNativeType (ptype);
2544                         }
2545
2546                         // now find the existing node, if it's there so we can reuse it.
2547                         var nodes = root.SelectSingleNode ("Parameters").SelectNodes ("Parameter")
2548                                 .Cast<XmlElement> ().Where (x => x.GetAttribute ("Name") == p.Name)
2549                                 .ToArray();
2550
2551                         if (nodes.Count () == 0) {
2552                                 // wasn't found, let's make sure it wasn't just cause the param name was changed
2553                                 nodes = root.SelectSingleNode ("Parameters").SelectNodes ("Parameter")
2554                                         .Cast<XmlElement> ()
2555                                         .Skip (i) // this makes sure we don't inadvertently "reuse" nodes when adding new ones
2556                                         .Where (x => x.GetAttribute ("Name") != p.Name && (x.GetAttribute ("Type") == ptype || x.GetAttribute ("Type") == newPType))
2557                                         .Take(1) // there might be more than one that meets this parameter ... only take the first.
2558                                         .ToArray();
2559                         }
2560
2561                         AddXmlNode (nodes, 
2562                                 x => x.GetAttribute ("Type") == ptype,
2563                                 x => x.SetAttribute ("Type", ptype),
2564                                 () => {
2565                                         pe = root.OwnerDocument.CreateElement ("Parameter");
2566                                         e.AppendChild (pe);
2567
2568                                         pe.SetAttribute ("Name", p.Name);
2569                                         pe.SetAttribute ("Type", ptype);
2570                                         if (p.ParameterType is ByReferenceType) {
2571                                                 if (p.IsOut)
2572                                                         pe.SetAttribute ("RefType", "out");
2573                                                 else
2574                                                         pe.SetAttribute ("RefType", "ref");
2575                                         }
2576
2577                                         MakeAttributes (pe, GetCustomAttributes (p.CustomAttributes, ""));
2578                                         return pe;
2579                                 },
2580                                 member);
2581
2582                         i++;
2583                 }
2584         }
2585         
2586         private void MakeTypeParameters (XmlElement root, IList<GenericParameter> typeParams, MemberReference member, bool shouldDuplicateWithNew)
2587         {
2588                 if (typeParams == null || typeParams.Count == 0) {
2589                         XmlElement f = (XmlElement) root.SelectSingleNode ("TypeParameters");
2590                         if (f != null)
2591                                 root.RemoveChild (f);
2592                         return;
2593                 }
2594                 XmlElement e = WriteElement(root, "TypeParameters");
2595
2596                 var nodes = e.SelectNodes ("TypeParameter").Cast<XmlElement> ().ToArray ();
2597
2598                 foreach (GenericParameter t in typeParams) {
2599
2600                                 IList<TypeReference> constraints = t.Constraints;
2601                                 GenericParameterAttributes attrs = t.Attributes;
2602
2603
2604                                 AddXmlNode (
2605                                         nodes,
2606                                         x => { 
2607                                                 var baseType = e.SelectSingleNode("BaseTypeName");
2608                                                 // TODO: should this comparison take into account BaseTypeName?
2609                                                 return x.GetAttribute("Name") == t.Name;
2610                                         },
2611                                         x => {}, // no additional action required
2612                                         () => {
2613
2614                                                 XmlElement pe = root.OwnerDocument.CreateElement("TypeParameter");
2615                                                 e.AppendChild(pe);
2616                                                 pe.SetAttribute("Name", t.Name);
2617                                                         MakeAttributes (pe, GetCustomAttributes (t.CustomAttributes, ""), t.DeclaringType);
2618                                                 XmlElement ce = (XmlElement) e.SelectSingleNode ("Constraints");
2619                                                 if (attrs == GenericParameterAttributes.NonVariant && constraints.Count == 0) {
2620                                                         if (ce != null)
2621                                                                 e.RemoveChild (ce);
2622                                                         return pe;
2623                                                 }
2624                                                 if (ce != null)
2625                                                         ce.RemoveAll();
2626                                                 else {
2627                                                         ce = root.OwnerDocument.CreateElement ("Constraints");
2628                                                 }
2629                                                 pe.AppendChild (ce);
2630                                                 if ((attrs & GenericParameterAttributes.Contravariant) != 0)
2631                                                         AppendElementText (ce, "ParameterAttribute", "Contravariant");
2632                                                 if ((attrs & GenericParameterAttributes.Covariant) != 0)
2633                                                         AppendElementText (ce, "ParameterAttribute", "Covariant");
2634                                                 if ((attrs & GenericParameterAttributes.DefaultConstructorConstraint) != 0)
2635                                                         AppendElementText (ce, "ParameterAttribute", "DefaultConstructorConstraint");
2636                                                 if ((attrs & GenericParameterAttributes.NotNullableValueTypeConstraint) != 0)
2637                                                         AppendElementText (ce, "ParameterAttribute", "NotNullableValueTypeConstraint");
2638                                                 if ((attrs & GenericParameterAttributes.ReferenceTypeConstraint) != 0)
2639                                                         AppendElementText (ce, "ParameterAttribute", "ReferenceTypeConstraint");
2640                                                 foreach (TypeReference c in constraints) {
2641                                                         TypeDefinition cd = c.Resolve ();
2642                                                         AppendElementText (ce,
2643                                                                         (cd != null && cd.IsInterface) ? "InterfaceName" : "BaseTypeName",
2644                                                                         GetDocTypeFullName (c));
2645                                                 }
2646                                         
2647                                                 return pe;
2648                                         },
2649                                 member);
2650                 }
2651         }
2652
2653         private void MakeParameters (XmlElement root, MemberReference mi, bool shouldDuplicateWithNew)
2654         {
2655                 if (mi is MethodDefinition && ((MethodDefinition) mi).IsConstructor)
2656                                 MakeParameters (root, mi, ((MethodDefinition)mi).Parameters, shouldDuplicateWithNew);
2657                 else if (mi is MethodDefinition) {
2658                         MethodDefinition mb = (MethodDefinition) mi;
2659                         IList<ParameterDefinition> parameters = mb.Parameters;
2660                                 MakeParameters(root, mi, parameters, shouldDuplicateWithNew);
2661                         if (parameters.Count > 0 && DocUtils.IsExtensionMethod (mb)) {
2662                                 XmlElement p = (XmlElement) root.SelectSingleNode ("Parameters/Parameter[position()=1]");
2663                                 p.SetAttribute ("RefType", "this");
2664                         }
2665                 }
2666                 else if (mi is PropertyDefinition) {
2667                         IList<ParameterDefinition> parameters = ((PropertyDefinition)mi).Parameters;
2668                         if (parameters.Count > 0)
2669                                         MakeParameters(root, mi, parameters, shouldDuplicateWithNew);
2670                         else
2671                                 return;
2672                 }
2673                 else if (mi is FieldDefinition) return;
2674                 else if (mi is EventDefinition) return;
2675                 else throw new ArgumentException();
2676         }
2677
2678         internal static string GetDocParameterType (TypeReference type)
2679         {
2680                 return GetDocTypeFullName (type).Replace ("@", "&");
2681         }
2682
2683         private void MakeReturnValue (XmlElement root, TypeReference type, IList<CustomAttribute> attributes, bool shouldDuplicateWithNew=false) 
2684                 {
2685                         XmlElement e = WriteElement(root, "ReturnValue");
2686                         var valueToUse = GetDocTypeFullName (type);
2687
2688                         AddXmlNode (e.SelectNodes("ReturnType").Cast<XmlElement> ().ToArray (),
2689                                 x => x.InnerText == valueToUse,
2690                                 x => x.InnerText = valueToUse,
2691                                 () => {
2692                                         var newNode = WriteElementText(e, "ReturnType", valueToUse, forceNewElement: true);
2693                                         if (attributes != null)
2694                                                 MakeAttributes(e, GetCustomAttributes (attributes, ""), type);
2695
2696                                         return newNode;
2697                                 },
2698                         type);
2699         }
2700         
2701         private void MakeReturnValue (XmlElement root, MemberReference mi, bool shouldDuplicateWithNew=false)
2702         {
2703                 if (mi is MethodDefinition && ((MethodDefinition) mi).IsConstructor)
2704                         return;
2705                 else if (mi is MethodDefinition)
2706                         MakeReturnValue (root, ((MethodDefinition)mi).ReturnType, ((MethodDefinition)mi).MethodReturnType.CustomAttributes, shouldDuplicateWithNew);
2707                 else if (mi is PropertyDefinition)
2708                         MakeReturnValue (root, ((PropertyDefinition)mi).PropertyType, null, shouldDuplicateWithNew);
2709                 else if (mi is FieldDefinition)
2710                         MakeReturnValue (root, ((FieldDefinition)mi).FieldType, null, shouldDuplicateWithNew);
2711                 else if (mi is EventDefinition)
2712                         MakeReturnValue (root, ((EventDefinition)mi).EventType, null, shouldDuplicateWithNew);
2713                 else
2714                         throw new ArgumentException(mi + " is a " + mi.GetType().FullName);
2715         }
2716         
2717         private XmlElement MakeMember(XmlDocument doc, DocsNodeInfo info)
2718         {
2719                 MemberReference mi = info.Member;
2720                 if (mi is TypeDefinition) return null;
2721
2722                 string sigs = memberFormatters [0].GetDeclaration (mi);
2723                 if (sigs == null) return null; // not publicly visible
2724                 
2725                 // no documentation for property/event accessors.  Is there a better way of doing this?
2726                 if (mi.Name.StartsWith("get_")) return null;
2727                 if (mi.Name.StartsWith("set_")) return null;
2728                 if (mi.Name.StartsWith("add_")) return null;
2729                 if (mi.Name.StartsWith("remove_")) return null;
2730                 if (mi.Name.StartsWith("raise_")) return null;
2731                 
2732                 XmlElement me = doc.CreateElement("Member");
2733                 me.SetAttribute("MemberName", GetMemberName (mi));
2734
2735                 info.Node = me;
2736                 UpdateMember(info);
2737                 if (exceptions.HasValue && 
2738                                 (exceptions.Value & ExceptionLocations.AddedMembers) != 0)
2739                         UpdateExceptions (info.Node, info.Member);
2740
2741                 if (since != null) {
2742                         XmlNode docs = me.SelectSingleNode("Docs");
2743                         docs.AppendChild (CreateSinceNode (doc));
2744                 }
2745                 
2746                 return me;
2747         }
2748
2749         internal static string GetMemberName (MemberReference mi)
2750         {
2751                 MethodDefinition mb = mi as MethodDefinition;
2752                 if (mb == null) {
2753                         PropertyDefinition pi = mi as PropertyDefinition;
2754                         if (pi == null)
2755                                 return mi.Name;
2756                         return DocUtils.GetPropertyName (pi);
2757                 }
2758                 StringBuilder sb = new StringBuilder (mi.Name.Length);
2759                 if (!DocUtils.IsExplicitlyImplemented (mb))
2760                         sb.Append (mi.Name);
2761                 else {
2762                         TypeReference iface;
2763                         MethodReference ifaceMethod;
2764                         DocUtils.GetInfoForExplicitlyImplementedMethod (mb, out iface, out ifaceMethod);
2765                         sb.Append (GetDocTypeFullName (iface));
2766                         sb.Append ('.');
2767                         sb.Append (ifaceMethod.Name);
2768                 }
2769                 if (mb.IsGenericMethod ()) {
2770                         IList<GenericParameter> typeParams = mb.GenericParameters;
2771                         if (typeParams.Count > 0) {
2772                                 sb.Append ("<");
2773                                 sb.Append (typeParams [0].Name);
2774                                 for (int i = 1; i < typeParams.Count; ++i)
2775                                         sb.Append (",").Append (typeParams [i].Name);
2776                                 sb.Append (">");
2777                         }
2778                 }
2779                 return sb.ToString ();
2780         }
2781         
2782         /// SIGNATURE GENERATION FUNCTIONS
2783         internal static bool IsPrivate (MemberReference mi)
2784         {
2785                 return memberFormatters [0].GetDeclaration (mi) == null;
2786         }
2787
2788         internal static string GetMemberType (MemberReference mi)
2789         {
2790                 if (mi is MethodDefinition && ((MethodDefinition) mi).IsConstructor)
2791                         return "Constructor";
2792                 if (mi is MethodDefinition)
2793                         return "Method";
2794                 if (mi is PropertyDefinition)
2795                         return "Property";
2796                 if (mi is FieldDefinition)
2797                         return "Field";
2798                 if (mi is EventDefinition)
2799                         return "Event";
2800                 throw new ArgumentException();
2801         }
2802
2803         private static string GetDocTypeName (TypeReference type)
2804         {
2805                 return docTypeFormatter.GetName (type);
2806         }
2807
2808         internal static string GetDocTypeFullName (TypeReference type)
2809         {
2810                 return DocTypeFullMemberFormatter.Default.GetName (type);
2811         }
2812
2813         internal static string GetXPathForMember (DocumentationMember member)
2814         {
2815                 StringBuilder xpath = new StringBuilder ();
2816                 xpath.Append ("//Members/Member[@MemberName=\"")
2817                         .Append (member.MemberName)
2818                         .Append ("\"]");
2819                 if (member.Parameters != null && member.Parameters.Count > 0) {
2820                         xpath.Append ("/Parameters[count(Parameter) = ")
2821                                 .Append (member.Parameters.Count);
2822                         for (int i = 0; i < member.Parameters.Count; ++i) {
2823                                 xpath.Append (" and Parameter [").Append (i+1).Append ("]/@Type=\"");
2824                                 xpath.Append (member.Parameters [i]);
2825                                 xpath.Append ("\"");
2826                         }
2827                         xpath.Append ("]/..");
2828                 }
2829                 return xpath.ToString ();
2830         }
2831
2832         public static string GetXPathForMember (XPathNavigator member)
2833         {
2834                 StringBuilder xpath = new StringBuilder ();
2835                 xpath.Append ("//Type[@FullName=\"")
2836                         .Append (member.SelectSingleNode ("../../@FullName").Value)
2837                         .Append ("\"]/");
2838                 xpath.Append ("Members/Member[@MemberName=\"")
2839                         .Append (member.SelectSingleNode ("@MemberName").Value)
2840                         .Append ("\"]");
2841                 XPathNodeIterator parameters = member.Select ("Parameters/Parameter");
2842                 if (parameters.Count > 0) {
2843                         xpath.Append ("/Parameters[count(Parameter) = ")
2844                                 .Append (parameters.Count);
2845                         int i = 0;
2846                         while (parameters.MoveNext ()) {
2847                                 ++i;
2848                                 xpath.Append (" and Parameter [").Append (i).Append ("]/@Type=\"");
2849                                 xpath.Append (parameters.Current.Value);
2850                                 xpath.Append ("\"");
2851                         }
2852                         xpath.Append ("]/..");
2853                 }
2854                 return xpath.ToString ();
2855         }
2856
2857         public static string GetXPathForMember (MemberReference member)
2858         {
2859                 StringBuilder xpath = new StringBuilder ();
2860                 xpath.Append ("//Type[@FullName=\"")
2861                         .Append (member.DeclaringType.FullName)
2862                         .Append ("\"]/");
2863                 xpath.Append ("Members/Member[@MemberName=\"")
2864                         .Append (GetMemberName (member))
2865                         .Append ("\"]");
2866
2867                 IList<ParameterDefinition> parameters = null;
2868                 if (member is MethodDefinition)
2869                         parameters = ((MethodDefinition) member).Parameters;
2870                 else if (member is PropertyDefinition) {
2871                         parameters = ((PropertyDefinition) member).Parameters;
2872                 }
2873                 if (parameters != null && parameters.Count > 0) {
2874                         xpath.Append ("/Parameters[count(Parameter) = ")
2875                                 .Append (parameters.Count);
2876                         for (int i = 0; i < parameters.Count; ++i) {
2877                                 xpath.Append (" and Parameter [").Append (i+1).Append ("]/@Type=\"");
2878                                 xpath.Append (GetDocParameterType (parameters [i].ParameterType));
2879                                 xpath.Append ("\"");
2880                         }
2881                         xpath.Append ("]/..");
2882                 }
2883                 return xpath.ToString ();
2884         }
2885 }
2886
2887 static class CecilExtensions {
2888         public static string GetDeclaringType(this CustomAttribute attribute)
2889         {
2890                         var type = attribute.Constructor.DeclaringType;
2891                         var typeName = type.FullName;
2892
2893                         string translatedType = NativeTypeManager.GetTranslatedName (type);
2894                         return translatedType;
2895         }
2896
2897         public static IEnumerable<MemberReference> GetMembers (this TypeDefinition type)
2898         {
2899                 foreach (var c in type.Methods.Where (m => m.IsConstructor))
2900                         yield return (MemberReference) c;
2901                 foreach (var e in type.Events)
2902                         yield return (MemberReference) e;
2903                 foreach (var f in type.Fields)
2904                         yield return (MemberReference) f;
2905                 foreach (var m in type.Methods.Where (m => !m.IsConstructor))
2906                         yield return (MemberReference) m;
2907                 foreach (var t in type.NestedTypes)
2908                         yield return (MemberReference) t;
2909                 foreach (var p in type.Properties)
2910                         yield return (MemberReference) p;
2911         }
2912
2913         public static IEnumerable<MemberReference> GetMembers (this TypeDefinition type, string member)
2914         {
2915                 return GetMembers (type).Where (m => m.Name == member);
2916         }
2917
2918         public static MemberReference GetMember (this TypeDefinition type, string member)
2919         {
2920                 return GetMembers (type, member).EnsureZeroOrOne ();
2921         }
2922
2923         static T EnsureZeroOrOne<T> (this IEnumerable<T> source)
2924         {
2925                 if (source.Count () > 1)
2926                         throw new InvalidOperationException ("too many matches");
2927                 return source.FirstOrDefault ();
2928         }
2929
2930         public static MethodDefinition GetMethod (this TypeDefinition type, string method)
2931         {
2932                 return type.Methods
2933                         .Where (m => m.Name == method)
2934                         .EnsureZeroOrOne ();
2935         }
2936
2937         public static IEnumerable<MemberReference> GetDefaultMembers (this TypeReference type)
2938         {
2939                 TypeDefinition def = type as TypeDefinition;
2940                 if (def == null)
2941                         return new MemberReference [0];
2942                 CustomAttribute defMemberAttr = def.CustomAttributes
2943                                 .FirstOrDefault (c => c.AttributeType.FullName == "System.Reflection.DefaultMemberAttribute");
2944                 if (defMemberAttr == null)
2945                         return new MemberReference [0];
2946                 string name = (string) defMemberAttr.ConstructorArguments [0].Value;
2947                 return def.Properties
2948                                 .Where (p => p.Name == name)
2949                                 .Select (p => (MemberReference) p);
2950         }
2951
2952         public static IEnumerable<TypeDefinition> GetTypes (this AssemblyDefinition assembly)
2953         {
2954                 return assembly.Modules.SelectMany (md => md.GetAllTypes ());
2955         }
2956
2957         public static TypeDefinition GetType (this AssemblyDefinition assembly, string type)
2958         {
2959                 return GetTypes (assembly)
2960                         .Where (td => td.FullName == type)
2961                         .EnsureZeroOrOne ();
2962         }
2963
2964         public static bool IsGenericType (this TypeReference type)
2965         {
2966                 return type.GenericParameters.Count > 0;
2967         }
2968
2969         public static bool IsGenericMethod (this MethodReference method)
2970         {
2971                 return method.GenericParameters.Count > 0;
2972         }
2973
2974         public static MemberReference Resolve (this MemberReference member)
2975         {
2976                 FieldReference fr = member as FieldReference;
2977                 if (fr != null)
2978                         return fr.Resolve ();
2979                 MethodReference mr = member as MethodReference;
2980                 if (mr != null)
2981                         return mr.Resolve ();
2982                 TypeReference tr = member as TypeReference;
2983                 if (tr != null)
2984                         return tr.Resolve ();
2985                 PropertyReference pr = member as PropertyReference;
2986                 if (pr != null)
2987                         return pr;
2988                 EventReference er = member as EventReference;
2989                 if (er != null)
2990                         return er;
2991                 throw new NotSupportedException ("Cannot find definition for " + member.ToString ());
2992         }
2993
2994         public static TypeReference GetUnderlyingType (this TypeDefinition type)
2995         {
2996                 if (!type.IsEnum)
2997                         return type;
2998                 return type.Fields.First (f => f.Name == "value__").FieldType;
2999         }
3000
3001         public static IEnumerable<TypeDefinition> GetAllTypes (this ModuleDefinition self)
3002         {
3003                 return self.Types.SelectMany (t => t.GetAllTypes ());
3004         }
3005
3006         static IEnumerable<TypeDefinition> GetAllTypes (this TypeDefinition self)
3007         {
3008                 yield return self;
3009
3010                 if (!self.HasNestedTypes)
3011                         yield break;
3012
3013                 foreach (var type in self.NestedTypes.SelectMany (t => t.GetAllTypes ()))
3014                         yield return type;
3015         }
3016 }
3017
3018 enum ApiStyle {
3019         Classic,
3020         Unified
3021 }
3022
3023 static class DocUtils {
3024
3025         public static bool DoesNotHaveApiStyle(this XmlElement element, ApiStyle style) {
3026                 string styleString = style.ToString ().ToLowerInvariant ();
3027                         string apistylevalue = element.GetAttribute ("apistyle");
3028                         return apistylevalue != styleString || string.IsNullOrWhiteSpace(apistylevalue);
3029         }
3030         public static bool HasApiStyle(this XmlElement element, ApiStyle style) {
3031                 string styleString = style.ToString ().ToLowerInvariant ();
3032                 return element.GetAttribute ("apistyle") == styleString;
3033         }
3034         public static bool HasApiStyle(this XmlNode node, ApiStyle style) 
3035         {
3036                 var attribute = node.Attributes ["apistyle"];
3037                 return attribute != null && attribute.Value == style.ToString ().ToLowerInvariant ();
3038         }
3039         public static void AddApiStyle(this XmlElement element, ApiStyle style) {
3040                 string styleString = style.ToString ().ToLowerInvariant ();
3041                 var existingValue = element.GetAttribute ("apistyle");
3042                 if (string.IsNullOrWhiteSpace (existingValue) || existingValue != styleString) {
3043                         element.SetAttribute ("apistyle", styleString);
3044                 }
3045         }
3046         public static void RemoveApiStyle (this XmlElement element, ApiStyle style) 
3047         {
3048                 string styleString = style.ToString ().ToLowerInvariant ();
3049                 string existingValue = element.GetAttribute ("apistyle");
3050                 if (string.IsNullOrWhiteSpace (existingValue) || existingValue == styleString) {
3051                         element.RemoveAttribute ("apistyle");
3052                 }
3053         }
3054         public static void RemoveApiStyle (this XmlNode node, ApiStyle style) 
3055         {
3056                 var styleAttribute = node.Attributes ["apistyle"];
3057                 if (styleAttribute != null && styleAttribute.Value == style.ToString ().ToLowerInvariant ()) {
3058                         node.Attributes.Remove (styleAttribute);
3059                 }
3060         }
3061
3062         public static bool IsExplicitlyImplemented (MethodDefinition method)
3063         {
3064                 return method.IsPrivate && method.IsFinal && method.IsVirtual;
3065         }
3066
3067         public static string GetTypeDotMember (string name)
3068         {
3069                 int startType, startMethod;
3070                 startType = startMethod = -1;
3071                 for (int i = 0; i < name.Length; ++i) {
3072                         if (name [i] == '.') {
3073                                 startType = startMethod;
3074                                 startMethod = i;
3075                         }
3076                 }
3077                 return name.Substring (startType+1);
3078         }
3079
3080         public static string GetMember (string name)
3081         {
3082                 int i = name.LastIndexOf ('.');
3083                 if (i == -1)
3084                         return name;
3085                 return name.Substring (i+1);
3086         }
3087
3088         public static void GetInfoForExplicitlyImplementedMethod (
3089                         MethodDefinition method, out TypeReference iface, out MethodReference ifaceMethod)
3090         {
3091                 iface = null;
3092                 ifaceMethod = null;
3093                 if (method.Overrides.Count != 1)
3094                         throw new InvalidOperationException ("Could not determine interface type for explicitly-implemented interface member " + method.Name);
3095                 iface = method.Overrides [0].DeclaringType;
3096                 ifaceMethod = method.Overrides [0];
3097         }
3098
3099         public static string GetPropertyName (PropertyDefinition pi)
3100         {
3101                 // Issue: (g)mcs-generated assemblies that explicitly implement
3102                 // properties don't specify the full namespace, just the 
3103                 // TypeName.Property; .NET uses Full.Namespace.TypeName.Property.
3104                 MethodDefinition method = pi.GetMethod;
3105                 if (method == null)
3106                         method = pi.SetMethod;
3107                 if (!IsExplicitlyImplemented (method))
3108                         return pi.Name;
3109
3110                 // Need to determine appropriate namespace for this member.
3111                 TypeReference iface;
3112                 MethodReference ifaceMethod;
3113                 GetInfoForExplicitlyImplementedMethod (method, out iface, out ifaceMethod);
3114                 return string.Join (".", new string[]{
3115                                 DocTypeFullMemberFormatter.Default.GetName (iface),
3116                                 GetMember (pi.Name)});
3117         }
3118
3119         public static string GetNamespace (TypeReference type)
3120         {
3121                 if (type.GetElementType ().IsNested)
3122                         type = type.GetElementType ();
3123                 while (type != null && type.IsNested)
3124                         type = type.DeclaringType;
3125                 if (type == null)
3126                         return string.Empty;
3127
3128                         string typeNS = type.Namespace;
3129
3130                         // first, make sure this isn't a type reference to another assembly/module
3131
3132                         bool isInAssembly = MDocUpdater.IsInAssemblies(type.Module.Name);
3133                         if (isInAssembly && !typeNS.StartsWith ("System") && MDocUpdater.HasDroppedNamespace (type)) {
3134                                 typeNS = string.Format ("{0}.{1}", MDocUpdater.droppedNamespace, typeNS);
3135                         }
3136                         return typeNS;
3137         }
3138
3139         public static string PathCombine (string dir, string path)
3140         {
3141                 if (dir == null)
3142                         dir = "";
3143                 if (path == null)
3144                         path = "";
3145                 return Path.Combine (dir, path);
3146         }
3147
3148         public static bool IsExtensionMethod (MethodDefinition method)
3149         {
3150                 return
3151                         method.CustomAttributes
3152                                         .Any (m => m.AttributeType.FullName == "System.Runtime.CompilerServices.ExtensionAttribute")
3153                         && method.DeclaringType.CustomAttributes
3154                                         .Any (m => m.AttributeType.FullName == "System.Runtime.CompilerServices.ExtensionAttribute");
3155         }
3156
3157         public static bool IsDelegate (TypeDefinition type)
3158         {
3159                 TypeReference baseRef = type.BaseType;
3160                 if (baseRef == null)
3161                         return false;
3162                 return !type.IsAbstract && baseRef.FullName == "System.Delegate" || // FIXME
3163                                 baseRef.FullName == "System.MulticastDelegate";
3164         }
3165
3166         public static List<TypeReference> GetDeclaringTypes (TypeReference type)
3167         {
3168                 List<TypeReference> decls = new List<TypeReference> ();
3169                 decls.Add (type);
3170                 while (type.DeclaringType != null) {
3171                         decls.Add (type.DeclaringType);
3172                         type = type.DeclaringType;
3173                 }
3174                 decls.Reverse ();
3175                 return decls;
3176         }
3177
3178         public static int GetGenericArgumentCount (TypeReference type)
3179         {
3180                 GenericInstanceType inst = type as GenericInstanceType;
3181                 return inst != null
3182                                 ? inst.GenericArguments.Count
3183                                 : type.GenericParameters.Count;
3184         }
3185
3186         public static IEnumerable<TypeReference> GetUserImplementedInterfaces (TypeDefinition type)
3187         {
3188                 HashSet<string> inheritedInterfaces = GetInheritedInterfaces (type);
3189                 List<TypeReference> userInterfaces = new List<TypeReference> ();
3190                 foreach (TypeReference iface in type.Interfaces) {
3191                         TypeReference lookup = iface.Resolve () ?? iface;
3192                         if (!inheritedInterfaces.Contains (GetQualifiedTypeName (lookup)))
3193                                 userInterfaces.Add (iface);
3194                 }
3195                 return userInterfaces.Where (i => MDocUpdater.IsPublic (i.Resolve ()));
3196         }
3197
3198         private static string GetQualifiedTypeName (TypeReference type)
3199         {
3200                 return "[" + type.Scope.Name + "]" + type.FullName;
3201         }
3202
3203         private static HashSet<string> GetInheritedInterfaces (TypeDefinition type)
3204         {
3205                 HashSet<string> inheritedInterfaces = new HashSet<string> ();
3206                 Action<TypeDefinition> a = null;
3207                 a = t => {
3208                         if (t == null) return;
3209                         foreach (TypeReference r in t.Interfaces) {
3210                                 inheritedInterfaces.Add (GetQualifiedTypeName (r));
3211                                 a (r.Resolve ());
3212                         }
3213                 };
3214                 TypeReference baseRef = type.BaseType;
3215                 while (baseRef != null) {
3216                         TypeDefinition baseDef = baseRef.Resolve ();
3217                         if (baseDef != null) {
3218                                 a (baseDef);
3219                                 baseRef = baseDef.BaseType;
3220                         }
3221                         else
3222                                 baseRef = null;
3223                 }
3224                 foreach (TypeReference r in type.Interfaces)
3225                         a (r.Resolve ());
3226                 return inheritedInterfaces;
3227         }
3228 }
3229
3230 class DocsNodeInfo {
3231         public DocsNodeInfo (XmlElement node)
3232         {
3233                 this.Node = node;
3234         }
3235
3236         public DocsNodeInfo (XmlElement node, TypeDefinition type)
3237                 : this (node)
3238         {
3239                 SetType (type);
3240         }
3241
3242         public DocsNodeInfo (XmlElement node, MemberReference member)
3243                 : this (node)
3244         {
3245                 SetMemberInfo (member);
3246         }
3247
3248         void SetType (TypeDefinition type)
3249         {
3250                 if (type == null)
3251                         throw new ArgumentNullException ("type");
3252                 Type = type;
3253                 GenericParameters = new List<GenericParameter> (type.GenericParameters);
3254                 List<TypeReference> declTypes = DocUtils.GetDeclaringTypes (type);
3255                 int maxGenArgs = DocUtils.GetGenericArgumentCount (type);
3256                 for (int i = 0; i < declTypes.Count - 1; ++i) {
3257                         int remove = System.Math.Min (maxGenArgs, 
3258                                         DocUtils.GetGenericArgumentCount (declTypes [i]));
3259                         maxGenArgs -= remove;
3260                         while (remove-- > 0)
3261                                 GenericParameters.RemoveAt (0);
3262                 }
3263                 if (DocUtils.IsDelegate (type)) {
3264                         Parameters = type.GetMethod("Invoke").Parameters;
3265                         ReturnType = type.GetMethod("Invoke").ReturnType;
3266                         ReturnIsReturn = true;
3267                 }
3268         }
3269
3270         void SetMemberInfo (MemberReference member)
3271         {
3272                 if (member == null)
3273                         throw new ArgumentNullException ("member");
3274                 ReturnIsReturn = true;
3275                 AddRemarks = true;
3276                 Member = member;
3277                 
3278                 if (member is MethodReference ) {
3279                         MethodReference mr = (MethodReference) member;
3280                         Parameters = mr.Parameters;
3281                         if (mr.IsGenericMethod ()) {
3282                                 GenericParameters = new List<GenericParameter> (mr.GenericParameters);
3283                         }
3284                 }
3285                 else if (member is PropertyDefinition) {
3286                         Parameters = ((PropertyDefinition) member).Parameters;
3287                 }
3288                         
3289                 if (member is MethodDefinition) {
3290                         ReturnType = ((MethodDefinition) member).ReturnType;
3291                 } else if (member is PropertyDefinition) {
3292                         ReturnType = ((PropertyDefinition) member).PropertyType;
3293                         ReturnIsReturn = false;
3294                 }
3295
3296                 // no remarks section for enum members
3297                 if (member.DeclaringType != null && ((TypeDefinition) member.DeclaringType).IsEnum)
3298                         AddRemarks = false;
3299         }
3300
3301         public TypeReference ReturnType;
3302         public List<GenericParameter> GenericParameters;
3303         public IList<ParameterDefinition> Parameters;
3304         public bool ReturnIsReturn;
3305         public XmlElement Node;
3306         public bool AddRemarks = true;
3307         public MemberReference Member;
3308         public TypeDefinition Type;
3309
3310         public override string ToString ()
3311         {
3312                 return string.Format ("{0} - {1} - {2}", Type, Member, Node == null ? "no xml" : "with xml");
3313         }
3314 }
3315
3316 class DocumentationEnumerator {
3317         
3318         public virtual IEnumerable<TypeDefinition> GetDocumentationTypes (AssemblyDefinition assembly, List<string> forTypes)
3319         {
3320                 return GetDocumentationTypes (assembly, forTypes, null);
3321         }
3322
3323         protected IEnumerable<TypeDefinition> GetDocumentationTypes (AssemblyDefinition assembly, List<string> forTypes, HashSet<string> seen)
3324         {
3325                 foreach (TypeDefinition type in assembly.GetTypes()) {
3326                         if (forTypes != null && forTypes.BinarySearch (type.FullName) < 0)
3327                                 continue;
3328                         if (seen != null && seen.Contains (type.FullName))
3329                                 continue;
3330                         yield return type;
3331                         foreach (TypeDefinition nested in type.NestedTypes)
3332                                 yield return nested;
3333                 }
3334         }
3335
3336         public virtual IEnumerable<DocsNodeInfo> GetDocumentationMembers (XmlDocument basefile, TypeDefinition type)
3337         {
3338                 foreach (XmlElement oldmember in basefile.SelectNodes("Type/Members/Member")) {
3339                         if (oldmember.GetAttribute ("__monodocer-seen__") == "true") {
3340                                 oldmember.RemoveAttribute ("__monodocer-seen__");
3341                                 continue;
3342                         }
3343                         MemberReference m = GetMember (type, new DocumentationMember (oldmember));
3344                         if (m == null) {
3345                                 yield return new DocsNodeInfo (oldmember);
3346                         }
3347                         else {
3348                                 yield return new DocsNodeInfo (oldmember, m);
3349                         }
3350                 }
3351         }
3352
3353         protected static MemberReference GetMember (TypeDefinition type, DocumentationMember member)
3354         {
3355                 string membertype = member.MemberType;
3356                 
3357                 string returntype = member.ReturnType;
3358                 
3359                 string docName = member.MemberName;
3360
3361                 string[] docTypeParams = GetTypeParameters (docName, member.TypeParameters);
3362
3363                 // If we're using 'magic types', then we might get false positives ... in those cases, we keep searching
3364                 MemberReference likelyCandidate = null;
3365                 
3366                 // Loop through all members in this type with the same name
3367                 var reflectedMembers = GetReflectionMembers (type, docName).ToArray ();
3368                 foreach (MemberReference mi in reflectedMembers) {
3369                         bool matchedMagicType = false;
3370                         if (mi is TypeDefinition) continue;
3371                         if (MDocUpdater.GetMemberType(mi) != membertype) continue;
3372
3373                         if (MDocUpdater.IsPrivate (mi))
3374                                 continue;
3375
3376                         IList<ParameterDefinition> pis = null;
3377                         string[] typeParams = null;
3378                         if (mi is MethodDefinition) {
3379                                 MethodDefinition mb = (MethodDefinition) mi;
3380                                 pis = mb.Parameters;
3381                                 if (mb.IsGenericMethod ()) {
3382                                         IList<GenericParameter> args = mb.GenericParameters;
3383                                         typeParams = args.Select (p => p.Name).ToArray ();
3384                                 }
3385                         }
3386                         else if (mi is PropertyDefinition)
3387                                 pis = ((PropertyDefinition)mi).Parameters;
3388                                 
3389                         // check type parameters
3390                         int methodTcount = member.TypeParameters == null ? 0 : member.TypeParameters.Count;
3391                         int reflectionTcount = typeParams == null ? 0 : typeParams.Length;
3392                         if (methodTcount != reflectionTcount) 
3393                                 continue;
3394
3395                         // check member parameters
3396                         int mcount = member.Parameters == null ? 0 : member.Parameters.Count;
3397                         int pcount = pis == null ? 0 : pis.Count;
3398                         if (mcount != pcount)
3399                                 continue;
3400
3401                         MethodDefinition mDef = mi as MethodDefinition;
3402                         if (mDef != null && !mDef.IsConstructor) {
3403                                 // Casting operators can overload based on return type.
3404                                 string rtype = GetReplacedString (
3405                                                        MDocUpdater.GetDocTypeFullName (((MethodDefinition)mi).ReturnType), 
3406                                                        typeParams, docTypeParams);
3407                                 string originalRType = rtype;
3408                                 if (MDocUpdater.SwitchingToMagicTypes) {
3409                                         rtype = NativeTypeManager.ConvertFromNativeType (rtype);
3410                                         
3411                                 }
3412                                 if ((returntype != rtype && originalRType == rtype) ||
3413                                         (MDocUpdater.SwitchingToMagicTypes && returntype != originalRType && returntype != rtype && originalRType != rtype)) {
3414                                         continue;
3415                                 }
3416
3417                                 if (originalRType != rtype)
3418                                         matchedMagicType = true;
3419                         }
3420
3421                         if (pcount == 0)
3422                                 return mi;
3423                         bool good = true;
3424                         for (int i = 0; i < pis.Count; i++) {
3425                                 string paramType = GetReplacedString (
3426                                         MDocUpdater.GetDocParameterType (pis [i].ParameterType),
3427                                         typeParams, docTypeParams);
3428
3429                                 // if magictypes, replace paramType to "classic value" ... so the comparison works
3430                                 string originalParamType = paramType;
3431                                 if (MDocUpdater.SwitchingToMagicTypes) {
3432                                         paramType = NativeTypeManager.ConvertFromNativeType (paramType);
3433                                 }
3434
3435                                 string xmlMemberType = member.Parameters [i];
3436                                 if ((!paramType.Equals(xmlMemberType) && paramType.Equals(originalParamType)) || 
3437                                         (MDocUpdater.SwitchingToMagicTypes && !originalParamType.Equals(xmlMemberType) && !paramType.Equals(xmlMemberType) && !paramType.Equals(originalParamType))) {
3438
3439                                         // did not match ... if we're dropping the namespace, and the paramType has the dropped
3440                                         // namespace, we should see if it matches when added
3441                                         bool stillDoesntMatch = true;
3442                                         if (MDocUpdater.HasDroppedNamespace(type) && paramType.StartsWith (MDocUpdater.droppedNamespace)) {
3443                                                 string withDroppedNs = string.Format ("{0}.{1}", MDocUpdater.droppedNamespace, xmlMemberType);
3444
3445                                                 stillDoesntMatch = withDroppedNs != paramType;
3446                                         }
3447
3448                                         if (stillDoesntMatch) {
3449                                                 good = false;
3450                                                 break;
3451                                         }
3452                                 }
3453
3454                                 if (originalParamType != paramType)
3455                                         matchedMagicType = true;
3456                         }
3457                         if (!good) continue;
3458
3459                         if (MDocUpdater.SwitchingToMagicTypes && likelyCandidate == null && matchedMagicType) {
3460                                 // we matched this on a magic type conversion ... let's keep going to see if there's another one we should look at that matches more closely
3461                                 likelyCandidate = mi;
3462                                 continue;
3463                         }
3464
3465                         return mi;
3466                 }
3467                 
3468                 return likelyCandidate;
3469         }
3470
3471         static string[] GetTypeParameters (string docName, IEnumerable<string> knownParameters)
3472         {
3473                 if (docName [docName.Length-1] != '>')
3474                         return null;
3475                 StringList types = new StringList ();
3476                 int endToken = docName.Length-2;
3477                 int i = docName.Length-2;
3478                 do {
3479                         if (docName [i] == ',' || docName [i] == '<') {
3480                                 types.Add (docName.Substring (i + 1, endToken - i));
3481                                 endToken = i-1;
3482                         }
3483                         if (docName [i] == '<')
3484                                 break;
3485                 } while (--i >= 0);
3486
3487                 types.Reverse ();
3488                 var arrayTypes = types.ToArray ();
3489
3490                 if (knownParameters != null && knownParameters.Any () && arrayTypes.Length != knownParameters.Count ())
3491                         return knownParameters.ToArray ();
3492                 else
3493                         return arrayTypes;
3494         }
3495
3496         protected static IEnumerable<MemberReference> GetReflectionMembers (TypeDefinition type, string docName)
3497         {
3498                 // In case of dropping the namespace, we have to remove the dropped NS
3499                 // so that docName will match what's in the assembly/type
3500                 if (MDocUpdater.HasDroppedNamespace (type) && docName.StartsWith(MDocUpdater.droppedNamespace + ".")) {
3501                         int droppedNsLength = MDocUpdater.droppedNamespace.Length;
3502                         docName = docName.Substring (droppedNsLength + 1, docName.Length - droppedNsLength - 1);
3503                 }
3504
3505                 // need to worry about 4 forms of //@MemberName values:
3506                 //  1. "Normal" (non-generic) member names: GetEnumerator
3507                 //    - Lookup as-is.
3508                 //  2. Explicitly-implemented interface member names: System.Collections.IEnumerable.Current
3509                 //    - try as-is, and try type.member (due to "kludge" for property
3510                 //      support.
3511                 //  3. "Normal" Generic member names: Sort<T> (CSC)
3512                 //    - need to remove generic parameters --> "Sort"
3513                 //  4. Explicitly-implemented interface members for generic interfaces: 
3514                 //    -- System.Collections.Generic.IEnumerable<T>.Current
3515                 //    - Try as-is, and try type.member, *keeping* the generic parameters.
3516                 //     --> System.Collections.Generic.IEnumerable<T>.Current, IEnumerable<T>.Current
3517                 //  5. As of 2008-01-02, gmcs will do e.g. 'IFoo`1[A].Method' instead of
3518                 //    'IFoo<A>.Method' for explicitly implemented methods; don't interpret
3519                 //    this as (1) or (2).
3520                 if (docName.IndexOf ('<') == -1 && docName.IndexOf ('[') == -1) {
3521                         // Cases 1 & 2
3522                         foreach (MemberReference mi in type.GetMembers (docName))
3523                                 yield return mi;
3524                         if (CountChars (docName, '.') > 0)
3525                                 // might be a property; try only type.member instead of
3526                                 // namespace.type.member.
3527                                 foreach (MemberReference mi in 
3528                                                 type.GetMembers (DocUtils.GetTypeDotMember (docName)))
3529                                         yield return mi;
3530                         yield break;
3531                 }
3532                 // cases 3 & 4
3533                 int numLt = 0;
3534                 int numDot = 0;
3535                 int startLt, startType, startMethod;
3536                 startLt = startType = startMethod = -1;
3537                 for (int i = 0; i < docName.Length; ++i) {
3538                         switch (docName [i]) {
3539                                 case '<':
3540                                         if (numLt == 0) {
3541                                                 startLt = i;
3542                                         }
3543                                         ++numLt;
3544                                         break;
3545                                 case '>':
3546                                         --numLt;
3547                                         if (numLt == 0 && (i + 1) < docName.Length)
3548                                                 // there's another character in docName, so this <...> sequence is
3549                                                 // probably part of a generic type -- case 4.
3550                                                 startLt = -1;
3551                                         break;
3552                                 case '.':
3553                                         startType = startMethod;
3554                                         startMethod = i;
3555                                         ++numDot;
3556                                         break;
3557                         }
3558                 }
3559                 string refName = startLt == -1 ? docName : docName.Substring (0, startLt);
3560                 // case 3
3561                 foreach (MemberReference mi in type.GetMembers (refName))
3562                         yield return mi;
3563
3564                 // case 4
3565                 foreach (MemberReference mi in type.GetMembers (refName.Substring (startType + 1)))
3566                         yield return mi;
3567
3568                 // If we _still_ haven't found it, we've hit another generic naming issue:
3569                 // post Mono 1.1.18, gmcs generates [[FQTN]] instead of <TypeName> for
3570                 // explicitly-implemented METHOD names (not properties), e.g. 
3571                 // "System.Collections.Generic.IEnumerable`1[[Foo, test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null]].GetEnumerator"
3572                 // instead of "System.Collections.Generic.IEnumerable<Foo>.GetEnumerator",
3573                 // which the XML docs will contain.
3574                 //
3575                 // Alas, we can't derive the Mono name from docName, so we need to iterate
3576                 // over all member names, convert them into CSC format, and compare... :-(
3577                 if (numDot == 0)
3578                         yield break;
3579                 foreach (MemberReference mi in type.GetMembers ()) {
3580                         if (MDocUpdater.GetMemberName (mi) == docName)
3581                                 yield return mi;
3582                 }
3583         }
3584
3585         static string GetReplacedString (string typeName, string[] from, string[] to)
3586         {
3587                 if (from == null)
3588                         return typeName;
3589                 for (int i = 0; i < from.Length; ++i)
3590                         typeName = typeName.Replace (from [i], to [i]);
3591                 return typeName;
3592         }
3593
3594         private static int CountChars (string s, char c)
3595         {
3596                 int count = 0;
3597                 for (int i = 0; i < s.Length; ++i) {
3598                         if (s [i] == c)
3599                                 ++count;
3600                 }
3601                 return count;
3602         }
3603 }
3604
3605 class EcmaDocumentationEnumerator : DocumentationEnumerator {
3606
3607         XmlReader ecmadocs;
3608         MDocUpdater app;
3609
3610         public EcmaDocumentationEnumerator (MDocUpdater app, XmlReader ecmaDocs)
3611         {
3612                 this.app      = app;
3613                 this.ecmadocs = ecmaDocs;
3614         }
3615
3616         public override IEnumerable<TypeDefinition> GetDocumentationTypes (AssemblyDefinition assembly, List<string> forTypes)
3617         {
3618                 HashSet<string> seen = new HashSet<string> ();
3619                 return GetDocumentationTypes (assembly, forTypes, seen)
3620                         .Concat (base.GetDocumentationTypes (assembly, forTypes, seen));
3621         }
3622
3623         new IEnumerable<TypeDefinition> GetDocumentationTypes (AssemblyDefinition assembly, List<string> forTypes, HashSet<string> seen)
3624         {
3625                 int typeDepth = -1;
3626                 while (ecmadocs.Read ()) {
3627                         switch (ecmadocs.Name) {
3628                                 case "Type": {
3629                                         if (typeDepth == -1)
3630                                                 typeDepth = ecmadocs.Depth;
3631                                         if (ecmadocs.NodeType != XmlNodeType.Element)
3632                                                 continue;
3633                                         if (typeDepth != ecmadocs.Depth) // nested <TypeDefinition/> element?
3634                                                 continue;
3635                                         string typename = ecmadocs.GetAttribute ("FullName");
3636                                         string typename2 = MDocUpdater.GetTypeFileName (typename);
3637                                         if (forTypes != null && 
3638                                                         forTypes.BinarySearch (typename) < 0 &&
3639                                                         typename != typename2 &&
3640                                                         forTypes.BinarySearch (typename2) < 0)
3641                                                 continue;
3642                                         TypeDefinition t;
3643                                         if ((t = assembly.GetType (typename)) == null && 
3644                                                         (t = assembly.GetType (typename2)) == null)
3645                                                 continue;
3646                                         seen.Add (typename);
3647                                         if (typename != typename2)
3648                                                 seen.Add (typename2);
3649                                         Console.WriteLine ("  Import: {0}", t.FullName);
3650                                         if (ecmadocs.Name != "Docs") {
3651                                                 int depth = ecmadocs.Depth;
3652                                                 while (ecmadocs.Read ()) {
3653                                                         if (ecmadocs.Name == "Docs" && ecmadocs.Depth == depth + 1)
3654                                                                 break;
3655                                                 }
3656                                         }
3657                                         if (!ecmadocs.IsStartElement ("Docs"))
3658                                                 throw new InvalidOperationException ("Found " + ecmadocs.Name + "; expecting <Docs/>!");
3659                                         yield return t;
3660                                         break;
3661                                 }
3662                                 default:
3663                                         break;
3664                         }
3665                 }
3666         }
3667
3668         public override IEnumerable<DocsNodeInfo> GetDocumentationMembers (XmlDocument basefile, TypeDefinition type)
3669         {
3670                 return GetMembers (basefile, type)
3671                         .Concat (base.GetDocumentationMembers (basefile, type));
3672         }
3673
3674         private IEnumerable<DocsNodeInfo> GetMembers (XmlDocument basefile, TypeDefinition type)
3675         {
3676                 while (ecmadocs.Name != "Members" && ecmadocs.Read ()) {
3677                         // do nothing
3678                 }
3679                 if (ecmadocs.IsEmptyElement)
3680                         yield break;
3681
3682                 int membersDepth = ecmadocs.Depth;
3683                 bool go = true;
3684                 while (go && ecmadocs.Read ()) {
3685                         switch (ecmadocs.Name) {
3686                                 case "Member": {
3687                                         if (membersDepth != ecmadocs.Depth - 1 || ecmadocs.NodeType != XmlNodeType.Element)
3688                                                 continue;
3689                                         DocumentationMember dm = new DocumentationMember (ecmadocs);
3690                                         
3691                                         string xp = MDocUpdater.GetXPathForMember (dm);
3692                                         XmlElement oldmember = (XmlElement) basefile.SelectSingleNode (xp);
3693                                         MemberReference m;
3694                                         if (oldmember == null) {
3695                                                 m = GetMember (type, dm);
3696                                                 if (m == null) {
3697                                                         app.Warning ("Could not import ECMA docs for `{0}'s `{1}': Member not found.",
3698                                                                         type.FullName, dm.MemberSignatures ["C#"]);
3699                                                                         // SelectSingleNode (ecmaDocsMember, "MemberSignature[@Language=\"C#\"]/@Value").Value);
3700                                                         continue;
3701                                                 }
3702                                                 // oldmember lookup may have failed due to type parameter renames.
3703                                                 // Try again.
3704                                                 oldmember = (XmlElement) basefile.SelectSingleNode (MDocUpdater.GetXPathForMember (m));
3705                                                 if (oldmember == null) {
3706                                                         XmlElement members = MDocUpdater.WriteElement (basefile.DocumentElement, "Members");
3707                                                         oldmember = basefile.CreateElement ("Member");
3708                                                         oldmember.SetAttribute ("MemberName", dm.MemberName);
3709                                                         members.AppendChild (oldmember);
3710                                                         foreach (string key in MDocUpdater.Sort (dm.MemberSignatures.Keys)) {
3711                                                                 XmlElement ms = basefile.CreateElement ("MemberSignature");
3712                                                                 ms.SetAttribute ("Language", key);
3713                                                                 ms.SetAttribute ("Value", (string) dm.MemberSignatures [key]);
3714                                                                 oldmember.AppendChild (ms);
3715                                                         }
3716                                                         oldmember.SetAttribute ("__monodocer-seen__", "true");
3717                                                         Console.WriteLine ("Member Added: {0}", oldmember.SelectSingleNode("MemberSignature[@Language='C#']/@Value").InnerText);
3718                                                         app.additions++;
3719                                                 }
3720                                         }
3721                                         else {
3722                                                 m = GetMember (type, new DocumentationMember (oldmember));
3723                                                 if (m == null) {
3724                                                         app.Warning ("Could not import ECMA docs for `{0}'s `{1}': Member not found.",
3725                                                                         type.FullName, dm.MemberSignatures ["C#"]);
3726                                                         continue;
3727                                                 }
3728                                                 oldmember.SetAttribute ("__monodocer-seen__", "true");
3729                                         }
3730                                         DocsNodeInfo node = new DocsNodeInfo (oldmember, m);
3731                                         if (ecmadocs.Name != "Docs")
3732                                                 throw new InvalidOperationException ("Found " + ecmadocs.Name + "; expected <Docs/>!");
3733                                         yield return node;
3734                                         break;
3735                                 }
3736                                 case "Members":
3737                                         if (membersDepth == ecmadocs.Depth && ecmadocs.NodeType == XmlNodeType.EndElement) {
3738                                                 go = false;
3739                                         }
3740                                         break;
3741                         }
3742                 }
3743         }
3744 }
3745
3746 abstract class DocumentationImporter {
3747
3748         public abstract void ImportDocumentation (DocsNodeInfo info);
3749 }
3750
3751 class MsxdocDocumentationImporter : DocumentationImporter {
3752
3753         XmlDocument slashdocs;
3754
3755         public MsxdocDocumentationImporter (string file)
3756         {
3757                 var xml = File.ReadAllText (file);
3758
3759                 // Ensure Unix line endings
3760                 xml = xml.Replace ("\r", "");
3761
3762                 slashdocs = new XmlDocument();
3763                 slashdocs.LoadXml (xml);
3764         }
3765
3766         public override void ImportDocumentation (DocsNodeInfo info)
3767         {
3768                 XmlNode elem = GetDocs (info.Member ?? info.Type);
3769
3770                 if (elem == null)
3771                         return;
3772
3773                 XmlElement e = info.Node;
3774
3775                 if (elem.SelectSingleNode("summary") != null)
3776                         MDocUpdater.ClearElement(e, "summary");
3777                 if (elem.SelectSingleNode("remarks") != null)
3778                         MDocUpdater.ClearElement(e, "remarks");
3779                 if (elem.SelectSingleNode ("value") != null || elem.SelectSingleNode ("returns") != null) {
3780                         MDocUpdater.ClearElement(e, "value");
3781                         MDocUpdater.ClearElement(e, "returns");
3782                 }
3783
3784                 foreach (XmlNode child in elem.ChildNodes) {
3785                         switch (child.Name) {
3786                                 case "param":
3787                                 case "typeparam": {
3788                                         XmlAttribute name = child.Attributes ["name"];
3789                                         if (name == null)
3790                                                 break;
3791                                         XmlElement p2 = (XmlElement) e.SelectSingleNode (child.Name + "[@name='" + name.Value + "']");
3792                                         if (p2 != null)
3793                                                 p2.InnerXml = child.InnerXml;
3794                                         break;
3795                                 }
3796                                 // Occasionally XML documentation will use <returns/> on
3797                                 // properties, so let's try to normalize things.
3798                                 case "value":
3799                                 case "returns": {
3800                                         XmlElement v = e.OwnerDocument.CreateElement (info.ReturnIsReturn ? "returns" : "value");
3801                                         v.InnerXml = child.InnerXml;
3802                                         e.AppendChild (v);
3803                                         break;
3804                                 }
3805                                 case "altmember":
3806                                 case "exception":
3807                                 case "permission": {
3808                                         XmlAttribute cref = child.Attributes ["cref"] ?? child.Attributes ["name"];
3809                                         if (cref == null)
3810                                                 break;
3811                                         XmlElement a = (XmlElement) e.SelectSingleNode (child.Name + "[@cref='" + cref.Value + "']");
3812                                         if (a == null) {
3813                                                 a = e.OwnerDocument.CreateElement (child.Name);
3814                                                 a.SetAttribute ("cref", cref.Value);
3815                                                 e.AppendChild (a);
3816                                         }
3817                                         a.InnerXml = child.InnerXml;
3818                                         break;
3819                                 }
3820                                 case "seealso": {
3821                                         XmlAttribute cref = child.Attributes ["cref"];
3822                                         if (cref == null)
3823                                                 break;
3824                                         XmlElement a = (XmlElement) e.SelectSingleNode ("altmember[@cref='" + cref.Value + "']");
3825                                         if (a == null) {
3826                                                 a = e.OwnerDocument.CreateElement ("altmember");
3827                                                 a.SetAttribute ("cref", cref.Value);
3828                                                 e.AppendChild (a);
3829                                         }
3830                                         break;
3831                                 }
3832                                 default: {
3833                                         bool add = true;
3834                                         if (child.NodeType == XmlNodeType.Element && 
3835                                                         e.SelectNodes (child.Name).Cast<XmlElement>().Any (n => n.OuterXml == child.OuterXml))
3836                                                 add = false;
3837                                         if (add)
3838                                                 MDocUpdater.CopyNode (child, e);
3839                                         break;
3840                                 }
3841                         }
3842                 }
3843         }
3844
3845         private XmlNode GetDocs (MemberReference member)
3846         {
3847                 string slashdocsig = MDocUpdater.slashdocFormatter.GetDeclaration (member);
3848                 if (slashdocsig != null)
3849                         return slashdocs.SelectSingleNode ("doc/members/member[@name='" + slashdocsig + "']");
3850                 return null;
3851         }
3852 }
3853
3854 class EcmaDocumentationImporter : DocumentationImporter {
3855
3856         XmlReader ecmadocs;
3857
3858         public EcmaDocumentationImporter (XmlReader ecmaDocs)
3859         {
3860                 this.ecmadocs = ecmaDocs;
3861         }
3862
3863         public override void ImportDocumentation (DocsNodeInfo info)
3864         {
3865                 if (!ecmadocs.IsStartElement ("Docs")) {
3866                         return;
3867                 }
3868
3869                 XmlElement e = info.Node;
3870
3871                 int depth = ecmadocs.Depth;
3872                 ecmadocs.ReadStartElement ("Docs");
3873                 while (ecmadocs.Read ()) {
3874                         if (ecmadocs.Name == "Docs") {
3875                                 if (ecmadocs.Depth == depth && ecmadocs.NodeType == XmlNodeType.EndElement)
3876                                         break;
3877                                 else
3878                                         throw new InvalidOperationException ("Skipped past current <Docs/> element!");
3879                         }
3880                         if (!ecmadocs.IsStartElement ())
3881                                 continue;
3882                         switch (ecmadocs.Name) {
3883                                 case "param":
3884                                 case "typeparam": {
3885                                         string name = ecmadocs.GetAttribute ("name");
3886                                         if (name == null)
3887                                                 break;
3888                                         XmlNode doc = e.SelectSingleNode (
3889                                                         ecmadocs.Name + "[@name='" + name + "']");
3890                                         string value = ecmadocs.ReadInnerXml ();
3891                                         if (doc != null)
3892                                                 doc.InnerXml = value.Replace ("\r", "");
3893                                         break;
3894                                 }
3895                                 case "altmember":
3896                                 case "exception":
3897                                 case "permission":
3898                                 case "seealso": {
3899                                         string name = ecmadocs.Name;
3900                                         string cref = ecmadocs.GetAttribute ("cref");
3901                                         if (cref == null)
3902                                                 break;
3903                                         XmlNode doc = e.SelectSingleNode (
3904                                                         ecmadocs.Name + "[@cref='" + cref + "']");
3905                                         string value = ecmadocs.ReadInnerXml ().Replace ("\r", "");
3906                                         if (doc != null)
3907                                                 doc.InnerXml = value;
3908                                         else {
3909                                                 XmlElement n = e.OwnerDocument.CreateElement (name);
3910                                                 n.SetAttribute ("cref", cref);
3911                                                 n.InnerXml = value;
3912                                                 e.AppendChild (n);
3913                                         }
3914                                         break;
3915                                 }
3916                                 default: {
3917                                         string name = ecmadocs.Name;
3918                                         string xpath = ecmadocs.Name;
3919                                         StringList attributes = new StringList (ecmadocs.AttributeCount);
3920                                         if (ecmadocs.MoveToFirstAttribute ()) {
3921                                                 do {
3922                                                         attributes.Add ("@" + ecmadocs.Name + "=\"" + ecmadocs.Value + "\"");
3923                                                 } while (ecmadocs.MoveToNextAttribute ());
3924                                                 ecmadocs.MoveToContent ();
3925                                         }
3926                                         if (attributes.Count > 0) {
3927                                                 xpath += "[" + string.Join (" and ", attributes.ToArray ()) + "]";
3928                                         }
3929                                         XmlNode doc = e.SelectSingleNode (xpath);
3930                                         string value = ecmadocs.ReadInnerXml ().Replace ("\r", "");
3931                                         if (doc != null) {
3932                                                 doc.InnerXml = value;
3933                                         }
3934                                         else {
3935                                                 XmlElement n = e.OwnerDocument.CreateElement (name);
3936                                                 n.InnerXml = value;
3937                                                 foreach (string a in attributes) {
3938                                                         int eq = a.IndexOf ('=');
3939                                                         n.SetAttribute (a.Substring (1, eq-1), a.Substring (eq+2, a.Length-eq-3));
3940                                                 }
3941                                                 e.AppendChild (n);
3942                                         }
3943                                         break;
3944                                 }
3945                         }
3946                 }
3947         }
3948 }
3949
3950 class DocumentationMember {
3951         public StringToStringMap MemberSignatures = new StringToStringMap ();
3952         public string ReturnType;
3953         public StringList Parameters;
3954         public StringList TypeParameters;
3955         public string MemberName;
3956         public string MemberType;
3957
3958         public DocumentationMember (XmlReader reader)
3959         {
3960                 MemberName = reader.GetAttribute ("MemberName");
3961                 int depth = reader.Depth;
3962                 bool go = true;
3963                 StringList p = new StringList ();
3964                 StringList tp = new StringList ();
3965                 do {
3966                         if (reader.NodeType != XmlNodeType.Element)
3967                                 continue;
3968
3969                         bool shouldUse = true;
3970                         try {
3971                                 string apistyle = reader.GetAttribute ("apistyle");
3972                                 shouldUse = string.IsNullOrWhiteSpace(apistyle) || apistyle == "classic"; // only use this tag if it's an 'classic' style node
3973                         }
3974                         catch (Exception ex) {}
3975                         switch (reader.Name) {
3976                                 case "MemberSignature":
3977                                         if (shouldUse) {
3978                                                 MemberSignatures [reader.GetAttribute ("Language")] = reader.GetAttribute ("Value");
3979                                         }
3980                                         break;
3981                                 case "MemberType":
3982                                         MemberType = reader.ReadElementString ();
3983                                         break;
3984                                 case "ReturnType":
3985                                         if (reader.Depth == depth + 2 && shouldUse)
3986                                                 ReturnType = reader.ReadElementString ();
3987                                         break;
3988                                 case "Parameter":
3989                                         if (reader.Depth == depth + 2 && shouldUse)
3990                                                 p.Add (reader.GetAttribute ("Type"));
3991                                         break;
3992                                 case "TypeParameter":
3993                                         if (reader.Depth == depth + 2 && shouldUse)
3994                                                 tp.Add (reader.GetAttribute ("Name"));
3995                                         break;
3996                                 case "Docs":
3997                                         if (reader.Depth == depth + 1)
3998                                                 go = false;
3999                                         break;
4000                         }
4001                 } while (go && reader.Read () && reader.Depth >= depth);
4002                 if (p.Count > 0) {
4003                         Parameters = p;
4004                 }
4005                 if (tp.Count > 0) {
4006                         TypeParameters = tp;
4007                 } else {
4008                         DiscernTypeParameters ();
4009                 }
4010         }
4011
4012         public DocumentationMember (XmlNode node)
4013         {
4014                 MemberName = node.Attributes ["MemberName"].Value;
4015                 foreach (XmlNode n in node.SelectNodes ("MemberSignature")) {
4016                         XmlAttribute l = n.Attributes ["Language"];
4017                         XmlAttribute v = n.Attributes ["Value"];
4018                         XmlAttribute apistyle = n.Attributes ["apistyle"];
4019                         bool shouldUse = apistyle == null || apistyle.Value == "classic";
4020                         if (l != null && v != null && shouldUse)
4021                                 MemberSignatures [l.Value] = v.Value;
4022                 }
4023                 MemberType = node.SelectSingleNode ("MemberType").InnerText;
4024                 XmlNode rt = node.SelectSingleNode ("ReturnValue/ReturnType[not(@apistyle) or @apistyle='classic']");
4025                 if (rt != null)
4026                         ReturnType = rt.InnerText;
4027                 XmlNodeList p = node.SelectNodes ("Parameters/Parameter[not(@apistyle) or @apistyle='classic']");
4028                 if (p.Count > 0) {
4029                         Parameters = new StringList (p.Count);
4030                         for (int i = 0; i < p.Count; ++i)
4031                                 Parameters.Add (p [i].Attributes ["Type"].Value);
4032                 }
4033                 XmlNodeList tp = node.SelectNodes ("TypeParameters/TypeParameter[not(@apistyle) or @apistyle='classic']");
4034                 if (tp.Count > 0) {
4035                         TypeParameters = new StringList (tp.Count);
4036                         for (int i = 0; i < tp.Count; ++i)
4037                                 TypeParameters.Add (tp [i].Attributes ["Name"].Value);
4038                 }
4039                 else {
4040                         DiscernTypeParameters ();
4041                 }
4042         }
4043
4044         void DiscernTypeParameters ()
4045         {
4046                 // see if we can discern the param list from the name
4047                 if (MemberName.Contains ("<") && MemberName.EndsWith (">")) {
4048                         var starti = MemberName.IndexOf ("<") + 1;
4049                         var endi = MemberName.LastIndexOf (">");
4050                         var paramlist = MemberName.Substring (starti, endi - starti);
4051                         var tparams = paramlist.Split (new char[] {','}, StringSplitOptions.RemoveEmptyEntries);
4052                         TypeParameters = new StringList (tparams);
4053                 }
4054         }
4055 }
4056
4057 public class DynamicParserContext {
4058         public ReadOnlyCollection<bool> TransformFlags;
4059         public int TransformIndex;
4060
4061         public DynamicParserContext (ICustomAttributeProvider provider)
4062         {
4063                 CustomAttribute da;
4064                 if (provider.HasCustomAttributes &&
4065                                 (da = (provider.CustomAttributes.Cast<CustomAttribute>()
4066                                         .SingleOrDefault (ca => ca.GetDeclaringType() == "System.Runtime.CompilerServices.DynamicAttribute"))) != null) {
4067                         CustomAttributeArgument[] values = da.ConstructorArguments.Count == 0
4068                                 ? new CustomAttributeArgument [0]
4069                                 : (CustomAttributeArgument[]) da.ConstructorArguments [0].Value;
4070
4071                         TransformFlags = new ReadOnlyCollection<bool> (values.Select (t => (bool) t.Value).ToArray());
4072                 }
4073         }
4074 }
4075
4076 public enum MemberFormatterState {
4077         None,
4078         WithinGenericTypeParameters,
4079 }
4080
4081 public abstract class MemberFormatter {
4082
4083         public virtual string Language {
4084                 get {return "";}
4085         }
4086
4087         public string GetName (MemberReference member)
4088         {
4089                 return GetName (member, null);
4090         }
4091
4092         public virtual string GetName (MemberReference member, DynamicParserContext context)
4093         {
4094                 TypeReference type = member as TypeReference;
4095                 if (type != null)
4096                         return GetTypeName (type, context);
4097                 MethodReference method  = member as MethodReference;
4098                 if (method != null && method.Name == ".ctor") // method.IsConstructor
4099                         return GetConstructorName (method);
4100                 if (method != null)
4101                         return GetMethodName (method);
4102                 PropertyReference prop = member as PropertyReference;
4103                 if (prop != null)
4104                         return GetPropertyName (prop);
4105                 FieldReference field = member as FieldReference;
4106                 if (field != null)
4107                         return GetFieldName (field);
4108                 EventReference e = member as EventReference;
4109                 if (e != null)
4110                         return GetEventName (e);
4111                 throw new NotSupportedException ("Can't handle: " +
4112                                         (member == null ? "null" : member.GetType().ToString()));
4113         }
4114
4115         protected virtual string GetTypeName (TypeReference type)
4116         {
4117                 return GetTypeName (type, null);
4118         }
4119
4120         protected virtual string GetTypeName (TypeReference type, DynamicParserContext context)
4121         {
4122                 if (type == null)
4123                         throw new ArgumentNullException ("type");
4124                 return _AppendTypeName (new StringBuilder (type.Name.Length), type, context).ToString ();
4125         }
4126
4127         protected virtual char[] ArrayDelimeters {
4128                 get {return new char[]{'[', ']'};}
4129         }
4130
4131         protected virtual MemberFormatterState MemberFormatterState { get; set; }
4132
4133         protected StringBuilder _AppendTypeName (StringBuilder buf, TypeReference type, DynamicParserContext context)
4134         {
4135                 if (type is ArrayType) {
4136                         TypeSpecification spec = type as TypeSpecification;
4137                         _AppendTypeName (buf, spec != null ? spec.ElementType : type.GetElementType (), context);
4138                         return AppendArrayModifiers (buf, (ArrayType) type);
4139                 }
4140                 if (type is ByReferenceType) {
4141                         return AppendRefTypeName (buf, type, context);
4142                 }
4143                 if (type is PointerType) {
4144                         return AppendPointerTypeName (buf, type, context);
4145                 }
4146                 if (type is GenericParameter) {
4147                         return AppendTypeName (buf, type, context);
4148                 }
4149                 AppendNamespace (buf, type);
4150                 GenericInstanceType genInst = type as GenericInstanceType;
4151                 if (type.GenericParameters.Count == 0 &&
4152                                 (genInst == null ? true : genInst.GenericArguments.Count == 0)) {
4153                         return AppendFullTypeName (buf, type, context);
4154                 }
4155                 return AppendGenericType (buf, type, context);
4156         }
4157
4158         protected virtual StringBuilder AppendNamespace (StringBuilder buf, TypeReference type)
4159         {
4160                 string ns = DocUtils.GetNamespace (type);
4161                 if (ns != null && ns.Length > 0)
4162                         buf.Append (ns).Append ('.');
4163                 return buf;
4164         }
4165
4166         protected virtual StringBuilder AppendFullTypeName (StringBuilder buf, TypeReference type, DynamicParserContext context)
4167         {
4168                 if (type.DeclaringType != null)
4169                         AppendFullTypeName (buf, type.DeclaringType, context).Append (NestedTypeSeparator);
4170                 return AppendTypeName (buf, type, context);
4171         }
4172
4173         protected virtual StringBuilder AppendTypeName (StringBuilder buf, TypeReference type, DynamicParserContext context)
4174         {
4175                 if (context != null)
4176                         context.TransformIndex++;
4177                 return AppendTypeName (buf, type.Name);
4178         }
4179
4180         protected virtual StringBuilder AppendTypeName (StringBuilder buf, string typename)
4181         {
4182                 int n = typename.IndexOf ("`");
4183                 if (n >= 0)
4184                         return buf.Append (typename.Substring (0, n));
4185                 return buf.Append (typename);
4186         }
4187
4188         protected virtual StringBuilder AppendArrayModifiers (StringBuilder buf, ArrayType array)
4189         {
4190                 buf.Append (ArrayDelimeters [0]);
4191                 int rank = array.Rank;
4192                 if (rank > 1)
4193                         buf.Append (new string (',', rank-1));
4194                 return buf.Append (ArrayDelimeters [1]);
4195         }
4196
4197         protected virtual string RefTypeModifier {
4198                 get {return "@";}
4199         }
4200
4201         protected virtual StringBuilder AppendRefTypeName (StringBuilder buf, TypeReference type, DynamicParserContext context)
4202         {
4203                 TypeSpecification spec = type as TypeSpecification;
4204                 return _AppendTypeName (buf, spec != null ? spec.ElementType : type.GetElementType (), context)
4205                                 .Append (RefTypeModifier);
4206         }
4207
4208         protected virtual string PointerModifier {
4209                 get {return "*";}
4210         }
4211
4212         protected virtual StringBuilder AppendPointerTypeName (StringBuilder buf, TypeReference type, DynamicParserContext context)
4213         {
4214                 TypeSpecification spec = type as TypeSpecification;
4215                 return _AppendTypeName (buf, spec != null ? spec.ElementType : type.GetElementType (), context)
4216                                 .Append (PointerModifier);
4217         }
4218
4219         protected virtual char[] GenericTypeContainer {
4220                 get {return new char[]{'<', '>'};}
4221         }
4222
4223         protected virtual char NestedTypeSeparator {
4224                 get {return '.';}
4225         }
4226
4227         protected virtual StringBuilder AppendGenericType (StringBuilder buf, TypeReference type, DynamicParserContext context)
4228         {
4229                 List<TypeReference> decls = DocUtils.GetDeclaringTypes (
4230                                 type is GenericInstanceType ? type.GetElementType () : type);
4231                 List<TypeReference> genArgs = GetGenericArguments (type);
4232                 int argIdx = 0;
4233                 int prev = 0;
4234                 bool insertNested = false;
4235                 foreach (var decl in decls) {
4236                         TypeReference declDef = decl.Resolve () ?? decl;
4237                         if (insertNested) {
4238                                 buf.Append (NestedTypeSeparator);
4239                         }
4240                         insertNested = true;
4241                         AppendTypeName (buf, declDef, context);
4242                         int ac = DocUtils.GetGenericArgumentCount (declDef);
4243                         int c = ac - prev;
4244                         prev = ac;
4245                         if (c > 0) {
4246                                 buf.Append (GenericTypeContainer [0]);
4247                                 var origState = MemberFormatterState;
4248                                 MemberFormatterState = MemberFormatterState.WithinGenericTypeParameters;
4249                                 _AppendTypeName (buf, genArgs [argIdx++], context);
4250                                 for (int i = 1; i < c; ++i) {
4251                                         _AppendTypeName (buf.Append (","), genArgs [argIdx++], context);
4252                                 }
4253                                 MemberFormatterState = origState;
4254                                 buf.Append (GenericTypeContainer [1]);
4255                         }
4256                 }
4257                 return buf;
4258         }
4259
4260         protected List<TypeReference> GetGenericArguments (TypeReference type)
4261         {
4262                 var args = new List<TypeReference> ();
4263                 GenericInstanceType inst = type as GenericInstanceType;
4264                 if (inst != null)
4265                         args.AddRange (inst.GenericArguments.Cast<TypeReference> ());
4266                 else
4267                         args.AddRange (type.GenericParameters.Cast<TypeReference> ());
4268                 return args;
4269         }
4270
4271         protected virtual StringBuilder AppendGenericTypeConstraints (StringBuilder buf, TypeReference type)
4272         {
4273                 return buf;
4274         }
4275
4276         protected virtual string GetConstructorName (MethodReference constructor)
4277         {
4278                 return constructor.Name;
4279         }
4280
4281         protected virtual string GetMethodName (MethodReference method)
4282         {
4283                 return method.Name;
4284         }
4285
4286         protected virtual string GetPropertyName (PropertyReference property)
4287         {
4288                 return property.Name;
4289         }
4290
4291         protected virtual string GetFieldName (FieldReference field)
4292         {
4293                 return field.Name;
4294         }
4295
4296         protected virtual string GetEventName (EventReference e)
4297         {
4298                 return e.Name;
4299         }
4300
4301         public virtual string GetDeclaration (MemberReference member)
4302         {
4303                 if (member == null)
4304                         throw new ArgumentNullException ("member");
4305                 TypeDefinition type = member as TypeDefinition;
4306                 if (type != null)
4307                         return GetTypeDeclaration (type);
4308                 MethodDefinition method = member as MethodDefinition;
4309                 if (method != null && method.IsConstructor)
4310                         return GetConstructorDeclaration (method);
4311                 if (method != null)
4312                         return GetMethodDeclaration (method);
4313                 PropertyDefinition prop = member as PropertyDefinition;
4314                 if (prop != null)
4315                         return GetPropertyDeclaration (prop);
4316                 FieldDefinition field = member as FieldDefinition;
4317                 if (field != null)
4318                         return GetFieldDeclaration (field);
4319                 EventDefinition e = member as EventDefinition;
4320                 if (e != null)
4321                         return GetEventDeclaration (e);
4322                 throw new NotSupportedException ("Can't handle: " + member.GetType().ToString());
4323         }
4324
4325         protected virtual string GetTypeDeclaration (TypeDefinition type)
4326         {
4327                 if (type == null)
4328                         throw new ArgumentNullException ("type");
4329                 StringBuilder buf = new StringBuilder (type.Name.Length);
4330                 _AppendTypeName (buf, type, null);
4331                 AppendGenericTypeConstraints (buf, type);
4332                 return buf.ToString ();
4333         }
4334
4335         protected virtual string GetConstructorDeclaration (MethodDefinition constructor)
4336         {
4337                 return GetConstructorName (constructor);
4338         }
4339
4340         protected virtual string GetMethodDeclaration (MethodDefinition method)
4341         {
4342                 if (method.HasCustomAttributes && method.CustomAttributes.Cast<CustomAttribute>().Any(
4343                                         ca => ca.GetDeclaringType() == "System.Diagnostics.Contracts.ContractInvariantMethodAttribute"))
4344                         return null;
4345
4346                 // Special signature for destructors.
4347                 if (method.Name == "Finalize" && method.Parameters.Count == 0)
4348                         return GetFinalizerName (method);
4349
4350                 StringBuilder buf = new StringBuilder ();
4351
4352                 AppendVisibility (buf, method);
4353                 if (buf.Length == 0 && 
4354                                 !(DocUtils.IsExplicitlyImplemented (method) && !method.IsSpecialName))
4355                         return null;
4356
4357                 AppendModifiers (buf, method);
4358
4359                 if (buf.Length != 0)
4360                         buf.Append (" ");
4361                 buf.Append (GetTypeName (method.ReturnType, new DynamicParserContext (method.MethodReturnType))).Append (" ");
4362
4363                 AppendMethodName (buf, method);
4364                 AppendGenericMethod (buf, method).Append (" ");
4365                 AppendParameters (buf, method, method.Parameters);
4366                 AppendGenericMethodConstraints (buf, method);
4367                 return buf.ToString ();
4368         }
4369
4370         protected virtual StringBuilder AppendMethodName (StringBuilder buf, MethodDefinition method)
4371         {
4372                 return buf.Append (method.Name);
4373         }
4374
4375         protected virtual string GetFinalizerName (MethodDefinition method)
4376         {
4377                 return "Finalize";
4378         }
4379
4380         protected virtual StringBuilder AppendVisibility (StringBuilder buf, MethodDefinition method)
4381         {
4382                 return buf;
4383         }
4384
4385         protected virtual StringBuilder AppendModifiers (StringBuilder buf, MethodDefinition method)
4386         {
4387                 return buf;
4388         }
4389
4390         protected virtual StringBuilder AppendGenericMethod (StringBuilder buf, MethodDefinition method)
4391         {
4392                 return buf;
4393         }
4394
4395         protected virtual StringBuilder AppendParameters (StringBuilder buf, MethodDefinition method, IList<ParameterDefinition> parameters)
4396         {
4397                 return buf;
4398         }
4399
4400         protected virtual StringBuilder AppendGenericMethodConstraints (StringBuilder buf, MethodDefinition method)
4401         {
4402                 return buf;
4403         }
4404
4405         protected virtual string GetPropertyDeclaration (PropertyDefinition property)
4406         {
4407                 return GetPropertyName (property);
4408         }
4409
4410         protected virtual string GetFieldDeclaration (FieldDefinition field)
4411         {
4412                 return GetFieldName (field);
4413         }
4414
4415         protected virtual string GetEventDeclaration (EventDefinition e)
4416         {
4417                 return GetEventName (e);
4418         }
4419 }
4420
4421 class ILFullMemberFormatter : MemberFormatter {
4422
4423         public override string Language {
4424                 get {return "ILAsm";}
4425         }
4426
4427         protected override char NestedTypeSeparator {
4428                 get {
4429                         return '/';
4430                 }
4431         }
4432
4433         protected override StringBuilder AppendNamespace (StringBuilder buf, TypeReference type)
4434         {
4435                 if (GetBuiltinType (type.FullName) != null)
4436                         return buf;
4437                 string ns = DocUtils.GetNamespace (type);
4438                 if (ns != null && ns.Length > 0) {
4439                         if (type.IsValueType)
4440                                 buf.Append ("valuetype ");
4441                         else
4442                                 buf.Append ("class ");
4443                         buf.Append (ns).Append ('.');
4444                 }
4445                 return buf;
4446         }
4447
4448         protected static string GetBuiltinType (string t)
4449         {
4450                 switch (t) {
4451                 case "System.Byte":    return "unsigned int8";
4452                 case "System.SByte":   return "int8";
4453                 case "System.Int16":   return "int16";
4454                 case "System.Int32":   return "int32";
4455                 case "System.Int64":   return "int64";
4456                 case "System.IntPtr":  return "native int";
4457
4458                 case "System.UInt16":  return "unsigned int16";
4459                 case "System.UInt32":  return "unsigned int32";
4460                 case "System.UInt64":  return "unsigned int64";
4461                 case "System.UIntPtr": return "native unsigned int";
4462
4463                 case "System.Single":  return "float32";
4464                 case "System.Double":  return "float64";
4465                 case "System.Boolean": return "bool";
4466                 case "System.Char":    return "char";
4467                 case "System.Void":    return "void";
4468                 case "System.String":  return "string";
4469                 case "System.Object":  return "object";
4470                 }
4471                 return null;
4472         }
4473
4474         protected override StringBuilder AppendTypeName (StringBuilder buf, string typename)
4475         {
4476                 return buf.Append (typename);
4477         }
4478
4479         protected override StringBuilder AppendTypeName (StringBuilder buf, TypeReference type, DynamicParserContext context)
4480         {
4481                 if (type is GenericParameter) {
4482                         AppendGenericParameterConstraints (buf, (GenericParameter) type).Append (type.Name);
4483                         return buf;
4484                 }
4485
4486                 string s = GetBuiltinType (type.FullName);
4487                 if (s != null) {
4488                         return buf.Append (s);
4489                 }
4490                 return base.AppendTypeName (buf, type, context);
4491         }
4492
4493         private StringBuilder AppendGenericParameterConstraints (StringBuilder buf, GenericParameter type)
4494         {
4495                 if (MemberFormatterState != MemberFormatterState.WithinGenericTypeParameters) {
4496                         return buf.Append (type.Owner is TypeReference ? "!" : "!!");
4497                 }
4498                 GenericParameterAttributes attrs = type.Attributes;
4499                 if ((attrs & GenericParameterAttributes.ReferenceTypeConstraint) != 0)
4500                         buf.Append ("class ");
4501                 if ((attrs & GenericParameterAttributes.NotNullableValueTypeConstraint) != 0)
4502                         buf.Append ("struct ");
4503                 if ((attrs & GenericParameterAttributes.DefaultConstructorConstraint) != 0)
4504                         buf.Append (".ctor ");
4505                 IList<TypeReference> constraints = type.Constraints;
4506                 MemberFormatterState = 0;
4507                 if (constraints.Count > 0) {
4508                         var full = new ILFullMemberFormatter ();
4509                         buf.Append ("(").Append (full.GetName (constraints [0]));
4510                         for (int i = 1; i < constraints.Count; ++i) {
4511                                 buf.Append (", ").Append (full.GetName (constraints [i]));
4512                         }
4513                         buf.Append (") ");
4514                 }
4515                 MemberFormatterState = MemberFormatterState.WithinGenericTypeParameters;
4516
4517                 if ((attrs & GenericParameterAttributes.Covariant) != 0)
4518                         buf.Append ("+ ");
4519                 if ((attrs & GenericParameterAttributes.Contravariant) != 0)
4520                         buf.Append ("- ");
4521                 return buf;
4522         }
4523
4524         protected override string GetTypeDeclaration (TypeDefinition type)
4525         {
4526                 string visibility = GetTypeVisibility (type.Attributes);
4527                 if (visibility == null)
4528                         return null;
4529
4530                 StringBuilder buf = new StringBuilder ();
4531
4532                 buf.Append (".class ");
4533                 if (type.IsNested)
4534                         buf.Append ("nested ");
4535                 buf.Append (visibility).Append (" ");
4536                 if (type.IsInterface)
4537                         buf.Append ("interface ");
4538                 if (type.IsSequentialLayout)
4539                         buf.Append ("sequential ");
4540                 if (type.IsAutoLayout)
4541                         buf.Append ("auto ");
4542                 if (type.IsAnsiClass)
4543                         buf.Append ("ansi ");
4544                 if (type.IsAbstract)
4545                         buf.Append ("abstract ");
4546                 if (type.IsSerializable)
4547                         buf.Append ("serializable ");
4548                 if (type.IsSealed)
4549                         buf.Append ("sealed ");
4550                 if (type.IsBeforeFieldInit)
4551                         buf.Append ("beforefieldinit ");
4552                 var state = MemberFormatterState;
4553                 MemberFormatterState = MemberFormatterState.WithinGenericTypeParameters;
4554                 buf.Append (GetName (type));
4555                 MemberFormatterState = state;
4556                 var full = new ILFullMemberFormatter ();
4557                 if (type.BaseType != null) {
4558                         buf.Append (" extends ");
4559                         if (type.BaseType.FullName == "System.Object")
4560                                 buf.Append ("System.Object");
4561                         else
4562                                 buf.Append (full.GetName (type.BaseType).Substring ("class ".Length));
4563                 }
4564                 bool first = true;
4565                 foreach (var name in type.Interfaces.Where (i => MDocUpdater.IsPublic (i.Resolve ()))
4566                                 .Select (i => full.GetName (i))
4567                                 .OrderBy (n => n)) {
4568                         if (first) {
4569                                 buf.Append (" implements ");
4570                                 first = false;
4571                         }
4572                         else {
4573                                 buf.Append (", ");
4574                         }
4575                         buf.Append (name);
4576                 }
4577
4578                 return buf.ToString ();
4579         }
4580
4581         protected override StringBuilder AppendGenericType (StringBuilder buf, TypeReference type, DynamicParserContext context)
4582         {
4583                 List<TypeReference> decls = DocUtils.GetDeclaringTypes (
4584                                 type is GenericInstanceType ? type.GetElementType () : type);
4585                 bool first = true;
4586                 foreach (var decl in decls) {
4587                         TypeReference declDef = decl.Resolve () ?? decl;
4588                         if (!first) {
4589                                 buf.Append (NestedTypeSeparator);
4590                         }
4591                         first = false;
4592                         AppendTypeName (buf, declDef, context);
4593                 }
4594                 buf.Append ('<');
4595                 first = true;
4596                 foreach (TypeReference arg in GetGenericArguments (type)) {
4597                         if (!first)
4598                                 buf.Append (", ");
4599                         first = false;
4600                         _AppendTypeName (buf, arg, context);
4601                 }
4602                 buf.Append ('>');
4603                 return buf;
4604         }
4605
4606         static string GetTypeVisibility (TypeAttributes ta)
4607         {
4608                 switch (ta & TypeAttributes.VisibilityMask) {
4609                 case TypeAttributes.Public:
4610                 case TypeAttributes.NestedPublic:
4611                         return "public";
4612
4613                 case TypeAttributes.NestedFamily:
4614                 case TypeAttributes.NestedFamORAssem:
4615                         return "protected";
4616
4617                 default:
4618                         return null;
4619                 }
4620         }
4621
4622         protected override string GetConstructorDeclaration (MethodDefinition constructor)
4623         {
4624                 return GetMethodDeclaration (constructor);
4625         }
4626
4627         protected override string GetMethodDeclaration (MethodDefinition method)
4628         {
4629                 if (method.IsPrivate && !DocUtils.IsExplicitlyImplemented (method))
4630                         return null;
4631
4632                 var buf = new StringBuilder ();
4633                 buf.Append (".method ");
4634                 AppendVisibility (buf, method);
4635                 if (method.IsStatic)
4636                         buf.Append ("static ");
4637                 if (method.IsHideBySig)
4638                         buf.Append ("hidebysig ");
4639                 if (method.IsPInvokeImpl) {
4640                         var info = method.PInvokeInfo;
4641                         buf.Append ("pinvokeimpl (\"")
4642                                 .Append (info.Module.Name)
4643                                 .Append ("\" as \"")
4644                                 .Append (info.EntryPoint)
4645                                 .Append ("\"");
4646                         if (info.IsCharSetAuto)
4647                                 buf.Append (" auto");
4648                         if (info.IsCharSetUnicode)
4649                                 buf.Append (" unicode");
4650                         if (info.IsCharSetAnsi)
4651                                 buf.Append (" ansi");
4652                         if (info.IsCallConvCdecl)
4653                                 buf.Append (" cdecl");
4654                         if (info.IsCallConvStdCall)
4655                                 buf.Append (" stdcall");
4656                         if (info.IsCallConvWinapi)
4657                                 buf.Append (" winapi");
4658                         if (info.IsCallConvThiscall)
4659                                 buf.Append (" thiscall");
4660                         if (info.SupportsLastError)
4661                                 buf.Append (" lasterr");
4662                         buf.Append (")");
4663                 }
4664                 if (method.IsSpecialName)
4665                         buf.Append ("specialname ");
4666                 if (method.IsRuntimeSpecialName)
4667                         buf.Append ("rtspecialname ");
4668                 if (method.IsNewSlot)
4669                         buf.Append ("newslot ");
4670                 if (method.IsVirtual)
4671                         buf.Append ("virtual ");
4672                 if (!method.IsStatic)
4673                         buf.Append ("instance ");
4674                 _AppendTypeName (buf, method.ReturnType, new DynamicParserContext (method.MethodReturnType));
4675                 buf.Append (' ')
4676                         .Append (method.Name);
4677                 if (method.IsGenericMethod ()) {
4678                         var state = MemberFormatterState;
4679                         MemberFormatterState = MemberFormatterState.WithinGenericTypeParameters;
4680                         IList<GenericParameter> args = method.GenericParameters;
4681                         if (args.Count > 0) {
4682                                 buf.Append ("<");
4683                                 _AppendTypeName (buf, args [0], null);
4684                                 for (int i = 1; i < args.Count; ++i)
4685                                         _AppendTypeName (buf.Append (", "), args [i], null);
4686                                 buf.Append (">");
4687                         }
4688                         MemberFormatterState = state;
4689                 }
4690
4691                 buf.Append ('(');
4692                 bool first = true;
4693                 for (int i = 0; i < method.Parameters.Count; ++i) {
4694                         if (!first)
4695                                 buf.Append (", ");
4696                         first = false;
4697                         _AppendTypeName (buf, method.Parameters [i].ParameterType, new DynamicParserContext (method.Parameters [i]));
4698                         buf.Append (' ');
4699                         buf.Append (method.Parameters [i].Name);
4700                 }
4701                 buf.Append (')');
4702                 if (method.IsIL)
4703                         buf.Append (" cil");
4704                 if (method.IsRuntime)
4705                         buf.Append (" runtime");
4706                 if (method.IsManaged)
4707                         buf.Append (" managed");
4708
4709                 return buf.ToString ();
4710         }
4711
4712         protected override StringBuilder AppendMethodName (StringBuilder buf, MethodDefinition method)
4713         {
4714                 if (DocUtils.IsExplicitlyImplemented (method)) {
4715                         TypeReference iface;
4716                         MethodReference ifaceMethod;
4717                         DocUtils.GetInfoForExplicitlyImplementedMethod (method, out iface, out ifaceMethod);
4718                         return buf.Append (new CSharpMemberFormatter ().GetName (iface))
4719                                 .Append ('.')
4720                                 .Append (ifaceMethod.Name);
4721                 }
4722                 return base.AppendMethodName (buf, method);
4723         }
4724
4725         protected override string RefTypeModifier {
4726                 get {return "";}
4727         }
4728
4729         protected override StringBuilder AppendVisibility (StringBuilder buf, MethodDefinition method)
4730         {
4731                 if (method.IsPublic)
4732                         return buf.Append ("public ");
4733                 if (method.IsFamilyAndAssembly)
4734                         return buf.Append ("familyandassembly");
4735                 if (method.IsFamilyOrAssembly)
4736                         return buf.Append ("familyorassembly");
4737                 if (method.IsFamily)
4738                         return buf.Append ("family");
4739                 return buf;
4740         }
4741
4742         protected override StringBuilder AppendModifiers (StringBuilder buf, MethodDefinition method)
4743         {
4744                 string modifiers = String.Empty;
4745                 if (method.IsStatic) modifiers += " static";
4746                 if (method.IsVirtual && !method.IsAbstract) {
4747                         if ((method.Attributes & MethodAttributes.NewSlot) != 0) modifiers += " virtual";
4748                         else modifiers += " override";
4749                 }
4750                 TypeDefinition declType = (TypeDefinition) method.DeclaringType;
4751                 if (method.IsAbstract && !declType.IsInterface) modifiers += " abstract";
4752                 if (method.IsFinal) modifiers += " sealed";
4753                 if (modifiers == " virtual sealed") modifiers = "";
4754
4755                 return buf.Append (modifiers);
4756         }
4757
4758         protected override StringBuilder AppendGenericMethod (StringBuilder buf, MethodDefinition method)
4759         {
4760                 if (method.IsGenericMethod ()) {
4761                         IList<GenericParameter> args = method.GenericParameters;
4762                         if (args.Count > 0) {
4763                                 buf.Append ("<");
4764                                 buf.Append (args [0].Name);
4765                                 for (int i = 1; i < args.Count; ++i)
4766                                         buf.Append (",").Append (args [i].Name);
4767                                 buf.Append (">");
4768                         }
4769                 }
4770                 return buf;
4771         }
4772
4773         protected override StringBuilder AppendParameters (StringBuilder buf, MethodDefinition method, IList<ParameterDefinition> parameters)
4774         {
4775                 return AppendParameters (buf, method, parameters, '(', ')');
4776         }
4777
4778         private StringBuilder AppendParameters (StringBuilder buf, MethodDefinition method, IList<ParameterDefinition> parameters, char begin, char end)
4779         {
4780                 buf.Append (begin);
4781
4782                 if (parameters.Count > 0) {
4783                         if (DocUtils.IsExtensionMethod (method))
4784                                 buf.Append ("this ");
4785                         AppendParameter (buf, parameters [0]);
4786                         for (int i = 1; i < parameters.Count; ++i) {
4787                                 buf.Append (", ");
4788                                 AppendParameter (buf, parameters [i]);
4789                         }
4790                 }
4791
4792                 return buf.Append (end);
4793         }
4794
4795         private StringBuilder AppendParameter (StringBuilder buf, ParameterDefinition parameter)
4796         {
4797                 if (parameter.ParameterType is ByReferenceType) {
4798                         if (parameter.IsOut)
4799                                 buf.Append ("out ");
4800                         else
4801                                 buf.Append ("ref ");
4802                 }
4803                 buf.Append (GetName (parameter.ParameterType)).Append (" ");
4804                 return buf.Append (parameter.Name);
4805         }
4806
4807         protected override string GetPropertyDeclaration (PropertyDefinition property)
4808         {
4809                 MethodDefinition gm = null, sm = null;
4810
4811                 string get_visible = null;
4812                 if ((gm = property.GetMethod) != null &&
4813                                 (DocUtils.IsExplicitlyImplemented (gm) ||
4814                                  (!gm.IsPrivate && !gm.IsAssembly && !gm.IsFamilyAndAssembly)))
4815                         get_visible = AppendVisibility (new StringBuilder (), gm).ToString ();
4816                 string set_visible = null;
4817                 if ((sm = property.SetMethod) != null &&
4818                                 (DocUtils.IsExplicitlyImplemented (sm) ||
4819                                  (!sm.IsPrivate && !sm.IsAssembly && !sm.IsFamilyAndAssembly)))
4820                         set_visible = AppendVisibility (new StringBuilder (), sm).ToString ();
4821
4822                 if ((set_visible == null) && (get_visible == null))
4823                         return null;
4824
4825                 StringBuilder buf = new StringBuilder ()
4826                         .Append (".property ");
4827                 if (!(gm ?? sm).IsStatic)
4828                         buf.Append ("instance ");
4829                 _AppendTypeName (buf, property.PropertyType, new DynamicParserContext (property));
4830                 buf.Append (' ').Append (property.Name);
4831                 if (!property.HasParameters || property.Parameters.Count == 0)
4832                         return buf.ToString ();
4833
4834                 buf.Append ('(');
4835                 bool first = true;
4836                 foreach (ParameterDefinition p in property.Parameters) {
4837                         if (!first)
4838                                 buf.Append (", ");
4839                         first = false;
4840                         _AppendTypeName (buf, p.ParameterType, new DynamicParserContext (p));
4841                 }
4842                 buf.Append (')');
4843
4844                 return buf.ToString ();
4845         }
4846
4847         protected override string GetFieldDeclaration (FieldDefinition field)
4848         {
4849                 TypeDefinition declType = (TypeDefinition) field.DeclaringType;
4850                 if (declType.IsEnum && field.Name == "value__")
4851                         return null; // This member of enums aren't documented.
4852
4853                 StringBuilder buf = new StringBuilder ();
4854                 AppendFieldVisibility (buf, field);
4855                 if (buf.Length == 0)
4856                         return null;
4857
4858                 buf.Insert (0, ".field ");
4859
4860                 if (field.IsStatic)
4861                         buf.Append ("static ");
4862                 if (field.IsInitOnly)
4863                         buf.Append ("initonly ");
4864                 if (field.IsLiteral)
4865                         buf.Append ("literal ");
4866                 _AppendTypeName (buf, field.FieldType, new DynamicParserContext (field));
4867                 buf.Append (' ').Append (field.Name);
4868                 AppendFieldValue (buf, field);
4869
4870                 return buf.ToString ();
4871         }
4872
4873         static StringBuilder AppendFieldVisibility (StringBuilder buf, FieldDefinition field)
4874         {
4875                 if (field.IsPublic)
4876                         return buf.Append ("public ");
4877                 if (field.IsFamilyAndAssembly)
4878                         return buf.Append ("familyandassembly ");
4879                 if (field.IsFamilyOrAssembly)
4880                         return buf.Append ("familyorassembly ");
4881                 if (field.IsFamily)
4882                         return buf.Append ("family ");
4883                 return buf;
4884         }
4885
4886         static StringBuilder AppendFieldValue (StringBuilder buf, FieldDefinition field)
4887         {
4888                 // enums have a value__ field, which we ignore
4889                 if (field.DeclaringType.IsGenericType ())
4890                         return buf;
4891                 if (field.HasConstant && field.IsLiteral) {
4892                         object val = null;
4893                         try {
4894                                 val   = field.Constant;
4895                         } catch {
4896                                 return buf;
4897                         }
4898                         if (val == null)
4899                                 buf.Append (" = ").Append ("null");
4900                         else if (val is Enum)
4901                                 buf.Append (" = ")
4902                                         .Append (GetBuiltinType (field.DeclaringType.GetUnderlyingType ().FullName))
4903                                         .Append ('(')
4904                                         .Append (val.ToString ())
4905                                         .Append (')');
4906                         else if (val is IFormattable) {
4907                                 string value = ((IFormattable)val).ToString();
4908                                 buf.Append (" = ");
4909                                 if (val is string)
4910                                         buf.Append ("\"" + value + "\"");
4911                                 else
4912                                         buf.Append (GetBuiltinType (field.DeclaringType.GetUnderlyingType ().FullName))
4913                                                 .Append ('(')
4914                                                 .Append (value)
4915                                                 .Append (')');
4916                         }
4917                 }
4918                 return buf;
4919         }
4920
4921         protected override string GetEventDeclaration (EventDefinition e)
4922         {
4923                 StringBuilder buf = new StringBuilder ();
4924                 if (AppendVisibility (buf, e.AddMethod).Length == 0) {
4925                         return null;
4926                 }
4927
4928                 buf.Length = 0;
4929                 buf.Append (".event ")
4930                         .Append (GetName (e.EventType))
4931                         .Append (' ')
4932                         .Append (e.Name);
4933
4934                 return buf.ToString ();
4935         }
4936 }
4937
4938 class ILMemberFormatter : ILFullMemberFormatter {
4939         protected override StringBuilder AppendNamespace (StringBuilder buf, TypeReference type)
4940         {
4941                 return buf;
4942         }
4943 }
4944
4945         class ILNativeTypeMemberFormatter : ILFullMemberFormatter {
4946                 protected static string _GetBuiltinType (string t)
4947                 {
4948                         //string moddedType = base.GetBuiltinType (t);
4949                         return null;
4950                         //return moddedType;
4951                 }
4952         }
4953
4954         class CSharpNativeTypeMemberFormatter : CSharpFullMemberFormatter {
4955                 protected override string GetCSharpType (string t) {
4956                         string moddedType = base.GetCSharpType (t);
4957
4958                         switch (moddedType) {
4959                         case "int":             return "nint";
4960                         case "uint":
4961                                 return "nuint";
4962                         case "float":
4963                                 return "nfloat";
4964                         case "System.Drawing.SizeF":
4965                                 return "CoreGraphics.CGSize";
4966                         case "System.Drawing.PointF":
4967                                 return "CoreGraphics.CGPoint";
4968                         case "System.Drawing.RectangleF":
4969                                 return "CoreGraphics.CGPoint";
4970                         }
4971                         return null;
4972                 }
4973         }
4974
4975 class CSharpFullMemberFormatter : MemberFormatter {
4976
4977         public override string Language {
4978                 get {return "C#";}
4979         }
4980
4981         protected override StringBuilder AppendNamespace (StringBuilder buf, TypeReference type)
4982         {
4983
4984                 string ns = DocUtils.GetNamespace (type);
4985                 if (GetCSharpType (type.FullName) == null && ns != null && ns.Length > 0 && ns != "System")
4986                         buf.Append (ns).Append ('.');
4987                 return buf;
4988         }
4989
4990         protected virtual string GetCSharpType (string t)
4991         {
4992                 switch (t) {
4993                 case "System.Byte":    return "byte";
4994                 case "System.SByte":   return "sbyte";
4995                 case "System.Int16":   return "short";
4996                 case "System.Int32":   return "int";
4997                 case "System.Int64":   return "long";
4998
4999                 case "System.UInt16":  return "ushort";
5000                 case "System.UInt32":  return "uint";
5001                 case "System.UInt64":  return "ulong";
5002
5003                 case "System.Single":  return "float";
5004                 case "System.Double":  return "double";
5005                 case "System.Decimal": return "decimal";
5006                 case "System.Boolean": return "bool";
5007                 case "System.Char":    return "char";
5008                 case "System.Void":    return "void";
5009                 case "System.String":  return "string";
5010                 case "System.Object":  return "object";
5011                 }
5012                 return null;
5013         }
5014
5015         protected override StringBuilder AppendTypeName (StringBuilder buf, TypeReference type, DynamicParserContext context)
5016         {
5017                 if (context != null && context.TransformFlags != null &&
5018                                 (context.TransformFlags.Count == 0 || context.TransformFlags [context.TransformIndex])) {
5019                         context.TransformIndex++;
5020                         return buf.Append ("dynamic");
5021                 }
5022
5023                 if (type is GenericParameter)
5024                         return AppendGenericParameterConstraints (buf, (GenericParameter) type, context).Append (type.Name);
5025                 string t = type.FullName;
5026                 if (!t.StartsWith ("System.")) {
5027                         return base.AppendTypeName (buf, type, context);
5028                 }
5029
5030                 string s = GetCSharpType (t);
5031                 if (s != null) {
5032                         if (context != null)
5033                                 context.TransformIndex++;
5034                         return buf.Append (s);
5035                 }
5036                 
5037                 return base.AppendTypeName (buf, type, context);
5038         }
5039
5040         private StringBuilder AppendGenericParameterConstraints (StringBuilder buf, GenericParameter type, DynamicParserContext context)
5041         {
5042                 if (MemberFormatterState != MemberFormatterState.WithinGenericTypeParameters)
5043                         return buf;
5044                 GenericParameterAttributes attrs = type.Attributes;
5045                 bool isout = (attrs & GenericParameterAttributes.Covariant) != 0;
5046                 bool isin  = (attrs & GenericParameterAttributes.Contravariant) != 0;
5047                 if (isin)
5048                         buf.Append ("in ");
5049                 else if (isout)
5050                         buf.Append ("out ");
5051                 return buf;
5052         }
5053
5054         protected override string GetTypeDeclaration (TypeDefinition type)
5055         {
5056                 string visibility = GetTypeVisibility (type.Attributes);
5057                 if (visibility == null)
5058                         return null;
5059
5060                 StringBuilder buf = new StringBuilder ();
5061                 
5062                 buf.Append (visibility);
5063                 buf.Append (" ");
5064
5065                 MemberFormatter full = new CSharpFullMemberFormatter ();
5066
5067                 if (DocUtils.IsDelegate (type)) {
5068                         buf.Append("delegate ");
5069                         MethodDefinition invoke = type.GetMethod ("Invoke");
5070                         buf.Append (full.GetName (invoke.ReturnType, new DynamicParserContext (invoke.MethodReturnType))).Append (" ");
5071                         buf.Append (GetName (type));
5072                         AppendParameters (buf, invoke, invoke.Parameters);
5073                         AppendGenericTypeConstraints (buf, type);
5074                         buf.Append (";");
5075
5076                         return buf.ToString();
5077                 }
5078                 
5079                 if (type.IsAbstract && !type.IsInterface)
5080                         buf.Append("abstract ");
5081                 if (type.IsSealed && !DocUtils.IsDelegate (type) && !type.IsValueType)
5082                         buf.Append("sealed ");
5083                 buf.Replace ("abstract sealed", "static");
5084
5085                 buf.Append (GetTypeKind (type));
5086                 buf.Append (" ");
5087                 buf.Append (GetCSharpType (type.FullName) == null 
5088                                 ? GetName (type) 
5089                                 : type.Name);
5090
5091                 if (!type.IsEnum) {
5092                         TypeReference basetype = type.BaseType;
5093                         if (basetype != null && basetype.FullName == "System.Object" || type.IsValueType)       // FIXME
5094                                 basetype = null;
5095
5096                         List<string> interface_names = DocUtils.GetUserImplementedInterfaces (type)
5097                                         .Select (iface => full.GetName (iface))
5098                                         .OrderBy (s => s)
5099                                         .ToList ();
5100
5101                         if (basetype != null || interface_names.Count > 0)
5102                                 buf.Append (" : ");
5103                         
5104                         if (basetype != null) {
5105                                 buf.Append (full.GetName (basetype));
5106                                 if (interface_names.Count > 0)
5107                                         buf.Append (", ");
5108                         }
5109                         
5110                         for (int i = 0; i < interface_names.Count; i++){
5111                                 if (i != 0)
5112                                         buf.Append (", ");
5113                                 buf.Append (interface_names [i]);
5114                         }
5115                         AppendGenericTypeConstraints (buf, type);
5116                 }
5117
5118                 return buf.ToString ();
5119         }
5120
5121         static string GetTypeKind (TypeDefinition t)
5122         {
5123                 if (t.IsEnum)
5124                         return "enum";
5125                 if (t.IsValueType)
5126                         return "struct";
5127                 if (t.IsClass || t.FullName == "System.Enum")
5128                         return "class";
5129                 if (t.IsInterface)
5130                         return "interface";
5131                 throw new ArgumentException(t.FullName);
5132         }
5133
5134         static string GetTypeVisibility (TypeAttributes ta)
5135         {
5136                 switch (ta & TypeAttributes.VisibilityMask) {
5137                 case TypeAttributes.Public:
5138                 case TypeAttributes.NestedPublic:
5139                         return "public";
5140
5141                 case TypeAttributes.NestedFamily:
5142                 case TypeAttributes.NestedFamORAssem:
5143                         return "protected";
5144
5145                 default:
5146                         return null;
5147                 }
5148         }
5149
5150         protected override StringBuilder AppendGenericTypeConstraints (StringBuilder buf, TypeReference type)
5151         {
5152                 if (type.GenericParameters.Count == 0)
5153                         return buf;
5154                 return AppendConstraints (buf, type.GenericParameters);
5155         }
5156
5157         private StringBuilder AppendConstraints (StringBuilder buf, IList<GenericParameter> genArgs)
5158         {
5159                 foreach (GenericParameter genArg in genArgs) {
5160                         GenericParameterAttributes attrs = genArg.Attributes;
5161                         IList<TypeReference> constraints = genArg.Constraints;
5162                         if (attrs == GenericParameterAttributes.NonVariant && constraints.Count == 0)
5163                                 continue;
5164
5165                         bool isref = (attrs & GenericParameterAttributes.ReferenceTypeConstraint) != 0;
5166                         bool isvt  = (attrs & GenericParameterAttributes.NotNullableValueTypeConstraint) != 0;
5167                         bool isnew = (attrs & GenericParameterAttributes.DefaultConstructorConstraint) != 0;
5168                         bool comma = false;
5169
5170                         if (!isref && !isvt && !isnew && constraints.Count == 0)
5171                                 continue;
5172                         buf.Append (" where ").Append (genArg.Name).Append (" : ");
5173                         if (isref) {
5174                                 buf.Append ("class");
5175                                 comma = true;
5176                         }
5177                         else if (isvt) {
5178                                 buf.Append ("struct");
5179                                 comma = true;
5180                         }
5181                         if (constraints.Count > 0 && !isvt) {
5182                                 if (comma)
5183                                         buf.Append (", ");
5184                                 buf.Append (GetTypeName (constraints [0]));
5185                                 for (int i = 1; i < constraints.Count; ++i)
5186                                         buf.Append (", ").Append (GetTypeName (constraints [i]));
5187                         }
5188                         if (isnew && !isvt) {
5189                                 if (comma)
5190                                         buf.Append (", ");
5191                                 buf.Append ("new()");
5192                         }
5193                 }
5194                 return buf;
5195         }
5196
5197         protected override string GetConstructorDeclaration (MethodDefinition constructor)
5198         {
5199                 StringBuilder buf = new StringBuilder ();
5200                 AppendVisibility (buf, constructor);
5201                 if (buf.Length == 0)
5202                         return null;
5203
5204                 buf.Append (' ');
5205                 base.AppendTypeName (buf, constructor.DeclaringType.Name).Append (' ');
5206                 AppendParameters (buf, constructor, constructor.Parameters);
5207                 buf.Append (';');
5208
5209                 return buf.ToString ();
5210         }
5211         
5212         protected override string GetMethodDeclaration (MethodDefinition method)
5213         {
5214                 string decl = base.GetMethodDeclaration (method);
5215                 if (decl != null)
5216                         return decl + ";";
5217                 return null;
5218         }
5219
5220         protected override StringBuilder AppendMethodName (StringBuilder buf, MethodDefinition method)
5221         {
5222                 if (DocUtils.IsExplicitlyImplemented (method)) {
5223                         TypeReference iface;
5224                         MethodReference ifaceMethod;
5225                         DocUtils.GetInfoForExplicitlyImplementedMethod (method, out iface, out ifaceMethod);
5226                         return buf.Append (new CSharpMemberFormatter ().GetName (iface))
5227                                 .Append ('.')
5228                                 .Append (ifaceMethod.Name);
5229                 }
5230                 return base.AppendMethodName (buf, method);
5231         }
5232
5233         protected override StringBuilder AppendGenericMethodConstraints (StringBuilder buf, MethodDefinition method)
5234         {
5235                 if (method.GenericParameters.Count == 0)
5236                         return buf;
5237                 return AppendConstraints (buf, method.GenericParameters);
5238         }
5239
5240         protected override string RefTypeModifier {
5241                 get {return "";}
5242         }
5243
5244         protected override string GetFinalizerName (MethodDefinition method)
5245         {
5246                 return "~" + method.DeclaringType.Name + " ()"; 
5247         }
5248
5249         protected override StringBuilder AppendVisibility (StringBuilder buf, MethodDefinition method)
5250         {
5251                 if (method == null)
5252                         return buf;
5253                 if (method.IsPublic)
5254                         return buf.Append ("public");
5255                 if (method.IsFamily || method.IsFamilyOrAssembly)
5256                         return buf.Append ("protected");
5257                 return buf;
5258         }
5259
5260         protected override StringBuilder AppendModifiers (StringBuilder buf, MethodDefinition method)
5261         {
5262                 string modifiers = String.Empty;
5263                 if (method.IsStatic) modifiers += " static";
5264                 if (method.IsVirtual && !method.IsAbstract) {
5265                         if ((method.Attributes & MethodAttributes.NewSlot) != 0) modifiers += " virtual";
5266                         else modifiers += " override";
5267                 }
5268                 TypeDefinition declType = (TypeDefinition) method.DeclaringType;
5269                 if (method.IsAbstract && !declType.IsInterface) modifiers += " abstract";
5270                 if (method.IsFinal) modifiers += " sealed";
5271                 if (modifiers == " virtual sealed") modifiers = "";
5272
5273                 return buf.Append (modifiers);
5274         }
5275
5276         protected override StringBuilder AppendGenericMethod (StringBuilder buf, MethodDefinition method)
5277         {
5278                 if (method.IsGenericMethod ()) {
5279                         IList<GenericParameter> args = method.GenericParameters;
5280                         if (args.Count > 0) {
5281                                 buf.Append ("<");
5282                                 buf.Append (args [0].Name);
5283                                 for (int i = 1; i < args.Count; ++i)
5284                                         buf.Append (",").Append (args [i].Name);
5285                                 buf.Append (">");
5286                         }
5287                 }
5288                 return buf;
5289         }
5290
5291         protected override StringBuilder AppendParameters (StringBuilder buf, MethodDefinition method, IList<ParameterDefinition> parameters)
5292         {
5293                 return AppendParameters (buf, method, parameters, '(', ')');
5294         }
5295
5296         private StringBuilder AppendParameters (StringBuilder buf, MethodDefinition method, IList<ParameterDefinition> parameters, char begin, char end)
5297         {
5298                 buf.Append (begin);
5299
5300                 if (parameters.Count > 0) {
5301                         if (DocUtils.IsExtensionMethod (method))
5302                                 buf.Append ("this ");
5303                         AppendParameter (buf, parameters [0]);
5304                         for (int i = 1; i < parameters.Count; ++i) {
5305                                 buf.Append (", ");
5306                                 AppendParameter (buf, parameters [i]);
5307                         }
5308                 }
5309
5310                 return buf.Append (end);
5311         }
5312
5313         private StringBuilder AppendParameter (StringBuilder buf, ParameterDefinition parameter)
5314         {
5315                 if (parameter.ParameterType is ByReferenceType) {
5316                         if (parameter.IsOut)
5317                                 buf.Append ("out ");
5318                         else
5319                                 buf.Append ("ref ");
5320                 }
5321                 buf.Append (GetTypeName (parameter.ParameterType, new DynamicParserContext (parameter))).Append (" ");
5322                 buf.Append (parameter.Name);
5323                 if (parameter.HasDefault && parameter.IsOptional && parameter.HasConstant) {
5324                         buf.AppendFormat (" = {0}", MDocUpdater.MakeAttributesValueString (parameter.Constant, parameter.ParameterType));
5325                 }
5326                 return buf;
5327         }
5328
5329         protected override string GetPropertyDeclaration (PropertyDefinition property)
5330         {
5331                 MethodDefinition method;
5332
5333                 string get_visible = null;
5334                 if ((method = property.GetMethod) != null && 
5335                                 (DocUtils.IsExplicitlyImplemented (method) || 
5336                                  (!method.IsPrivate && !method.IsAssembly && !method.IsFamilyAndAssembly)))
5337                         get_visible = AppendVisibility (new StringBuilder (), method).ToString ();
5338                 string set_visible = null;
5339                 if ((method = property.SetMethod) != null &&
5340                                 (DocUtils.IsExplicitlyImplemented (method) || 
5341                                  (!method.IsPrivate && !method.IsAssembly && !method.IsFamilyAndAssembly)))
5342                         set_visible = AppendVisibility (new StringBuilder (), method).ToString ();
5343
5344                 if ((set_visible == null) && (get_visible == null))
5345                         return null;
5346
5347                 string visibility;
5348                 StringBuilder buf = new StringBuilder ();
5349                 if (get_visible != null && (set_visible == null || (set_visible != null && get_visible == set_visible)))
5350                         buf.Append (visibility = get_visible);
5351                 else if (set_visible != null && get_visible == null)
5352                         buf.Append (visibility = set_visible);
5353                 else
5354                         buf.Append (visibility = "public");
5355
5356                 // Pick an accessor to use for static/virtual/override/etc. checks.
5357                 method = property.SetMethod;
5358                 if (method == null)
5359                         method = property.GetMethod;
5360         
5361                 string modifiers = String.Empty;
5362                 if (method.IsStatic) modifiers += " static";
5363                 if (method.IsVirtual && !method.IsAbstract) {
5364                                 if ((method.Attributes & MethodAttributes.NewSlot) != 0)
5365                                         modifiers += " virtual";
5366                                 else
5367                                         modifiers += " override";
5368                 }
5369                 TypeDefinition declDef = (TypeDefinition) method.DeclaringType;
5370                 if (method.IsAbstract && !declDef.IsInterface)
5371                         modifiers += " abstract";
5372                 if (method.IsFinal)
5373                         modifiers += " sealed";
5374                 if (modifiers == " virtual sealed")
5375                         modifiers = "";
5376                 buf.Append (modifiers).Append (' ');
5377
5378                 buf.Append (GetTypeName (property.PropertyType, new DynamicParserContext (property))).Append (' ');
5379
5380                 IEnumerable<MemberReference> defs = property.DeclaringType.GetDefaultMembers ();
5381                 string name = property.Name;
5382                 foreach (MemberReference mi in defs) {
5383                         if (mi == property) {
5384                                 name = "this";
5385                                 break;
5386                         }
5387                 }
5388                 buf.Append (name == "this" ? name : DocUtils.GetPropertyName (property));
5389         
5390                 if (property.Parameters.Count != 0) {
5391                         AppendParameters (buf, method, property.Parameters, '[', ']');
5392                 }
5393
5394                 buf.Append (" {");
5395                 if (get_visible != null) {
5396                         if (get_visible != visibility)
5397                                 buf.Append (' ').Append (get_visible);
5398                         buf.Append (" get;");
5399                 }
5400                 if (set_visible != null) {
5401                         if (set_visible != visibility)
5402                                 buf.Append (' ').Append (set_visible);
5403                         buf.Append (" set;");
5404                 }
5405                 buf.Append (" }");
5406         
5407                 return buf [0] != ' ' ? buf.ToString () : buf.ToString (1, buf.Length-1);
5408         }
5409
5410         protected override string GetFieldDeclaration (FieldDefinition field)
5411         {
5412                 TypeDefinition declType = (TypeDefinition) field.DeclaringType;
5413                 if (declType.IsEnum && field.Name == "value__")
5414                         return null; // This member of enums aren't documented.
5415
5416                 StringBuilder buf = new StringBuilder ();
5417                 AppendFieldVisibility (buf, field);
5418                 if (buf.Length == 0)
5419                         return null;
5420
5421                 if (declType.IsEnum)
5422                         return field.Name;
5423
5424                 if (field.IsStatic && !field.IsLiteral)
5425                         buf.Append (" static");
5426                 if (field.IsInitOnly)
5427                         buf.Append (" readonly");
5428                 if (field.IsLiteral)
5429                         buf.Append (" const");
5430
5431                 buf.Append (' ').Append (GetTypeName (field.FieldType, new DynamicParserContext (field))).Append (' ');
5432                 buf.Append (field.Name);
5433                 AppendFieldValue (buf, field);
5434                 buf.Append (';');
5435
5436                 return buf.ToString ();
5437         }
5438
5439         static StringBuilder AppendFieldVisibility (StringBuilder buf, FieldDefinition field)
5440         {
5441                 if (field.IsPublic)
5442                         return buf.Append ("public");
5443                 if (field.IsFamily || field.IsFamilyOrAssembly)
5444                         return buf.Append ("protected");
5445                 return buf;
5446         }
5447
5448         static StringBuilder AppendFieldValue (StringBuilder buf, FieldDefinition field)
5449         {
5450                 // enums have a value__ field, which we ignore
5451                 if (((TypeDefinition ) field.DeclaringType).IsEnum || 
5452                                 field.DeclaringType.IsGenericType ())
5453                         return buf;
5454                 if (field.HasConstant && field.IsLiteral) {
5455                         object val = null;
5456                         try {
5457                                 val   = field.Constant;
5458                         } catch {
5459                                 return buf;
5460                         }
5461                         if (val == null)
5462                                 buf.Append (" = ").Append ("null");
5463                         else if (val is Enum)
5464                                 buf.Append (" = ").Append (val.ToString ());
5465                         else if (val is IFormattable) {
5466                                 string value = ((IFormattable)val).ToString();
5467                                 if (val is string)
5468                                         value = "\"" + value + "\"";
5469                                 buf.Append (" = ").Append (value);
5470                         }
5471                 }
5472                 return buf;
5473         }
5474
5475         protected override string GetEventDeclaration (EventDefinition e)
5476         {
5477                 StringBuilder buf = new StringBuilder ();
5478                 if (AppendVisibility (buf, e.AddMethod).Length == 0) {
5479                         return null;
5480                 }
5481
5482                 AppendModifiers (buf, e.AddMethod);
5483
5484                 buf.Append (" event ");
5485                 buf.Append (GetTypeName (e.EventType, new DynamicParserContext (e.AddMethod.Parameters [0]))).Append (' ');
5486                 buf.Append (e.Name).Append (';');
5487
5488                 return buf.ToString ();
5489         }
5490 }
5491
5492 class CSharpMemberFormatter : CSharpFullMemberFormatter {
5493         protected override StringBuilder AppendNamespace (StringBuilder buf, TypeReference type)
5494         {
5495                 return buf;
5496         }
5497 }
5498
5499 class DocTypeFullMemberFormatter : MemberFormatter {
5500         public static readonly MemberFormatter Default = new DocTypeFullMemberFormatter ();
5501
5502         protected override char NestedTypeSeparator {
5503                 get {return '+';}
5504         }
5505 }
5506
5507 class DocTypeMemberFormatter : DocTypeFullMemberFormatter {
5508         protected override StringBuilder AppendNamespace (StringBuilder buf, TypeReference type)
5509         {
5510                 return buf;
5511         }
5512 }
5513
5514 class SlashDocMemberFormatter : MemberFormatter {
5515
5516         protected override char[] GenericTypeContainer {
5517                 get {return new char[]{'{', '}'};}
5518         }
5519
5520         private bool AddTypeCount = true;
5521
5522         private TypeReference genDeclType;
5523         private MethodReference genDeclMethod;
5524
5525         protected override StringBuilder AppendTypeName (StringBuilder buf, TypeReference type, DynamicParserContext context)
5526         {
5527                 if (type is GenericParameter) {
5528                         int l = buf.Length;
5529                         if (genDeclType != null) {
5530                                 IList<GenericParameter> genArgs = genDeclType.GenericParameters;
5531                                 for (int i = 0; i < genArgs.Count; ++i) {
5532                                         if (genArgs [i].Name == type.Name) {
5533                                                 buf.Append ('`').Append (i);
5534                                                 break;
5535                                         }
5536                                 }
5537                         }
5538                         if (genDeclMethod != null) {
5539                                 IList<GenericParameter> genArgs = null;
5540                                 if (genDeclMethod.IsGenericMethod ()) {
5541                                         genArgs = genDeclMethod.GenericParameters;
5542                                         for (int i = 0; i < genArgs.Count; ++i) {
5543                                                 if (genArgs [i].Name == type.Name) {
5544                                                         buf.Append ("``").Append (i);
5545                                                         break;
5546                                                 }
5547                                         }
5548                                 }
5549                         }
5550                         if (genDeclType == null && genDeclMethod == null) {
5551                                 // Probably from within an explicitly implemented interface member,
5552                                 // where CSC uses parameter names instead of indices (why?), e.g.
5553                                 // MyList`2.Mono#DocTest#Generic#IFoo{A}#Method``1(`0,``0) instead of
5554                                 // MyList`2.Mono#DocTest#Generic#IFoo{`0}#Method``1(`0,``0).
5555                                 buf.Append (type.Name);
5556                         }
5557                         if (buf.Length == l) {
5558                                 throw new Exception (string.Format (
5559                                                 "Unable to translate generic parameter {0}; genDeclType={1}, genDeclMethod={2}", 
5560                                                 type.Name, genDeclType, genDeclMethod));
5561                         }
5562                 }
5563                 else {
5564                         base.AppendTypeName (buf, type, context);
5565                         if (AddTypeCount) {
5566                                 int numArgs = type.GenericParameters.Count;
5567                                 if (type.DeclaringType != null)
5568                                         numArgs -= type.GenericParameters.Count;
5569                                 if (numArgs > 0) {
5570                                         buf.Append ('`').Append (numArgs);
5571                                 }
5572                         }
5573                 }
5574                 return buf;
5575         }
5576
5577         protected override StringBuilder AppendArrayModifiers (StringBuilder buf, ArrayType array)
5578         {
5579                 buf.Append (ArrayDelimeters [0]);
5580                 int rank = array.Rank;
5581                 if (rank > 1) {
5582                         buf.Append ("0:");
5583                         for (int i = 1; i < rank; ++i) {
5584                                 buf.Append (",0:");
5585                         }
5586                 }
5587                 return buf.Append (ArrayDelimeters [1]);
5588         }
5589
5590         protected override StringBuilder AppendGenericType (StringBuilder buf, TypeReference type, DynamicParserContext context)
5591         {
5592                 if (!AddTypeCount)
5593                         base.AppendGenericType (buf, type, context);
5594                 else
5595                         AppendType (buf, type, context);
5596                 return buf;
5597         }
5598
5599         private StringBuilder AppendType (StringBuilder buf, TypeReference type, DynamicParserContext context)
5600         {
5601                 List<TypeReference> decls = DocUtils.GetDeclaringTypes (type);
5602                 bool insertNested = false;
5603                 int prevParamCount = 0;
5604                 foreach (var decl in decls) {
5605                         if (insertNested)
5606                                 buf.Append (NestedTypeSeparator);
5607                         insertNested = true;
5608                         base.AppendTypeName (buf, decl, context);
5609                         int argCount = DocUtils.GetGenericArgumentCount (decl);
5610                         int numArgs = argCount - prevParamCount;
5611                         prevParamCount = argCount;
5612                         if (numArgs > 0)
5613                                 buf.Append ('`').Append (numArgs);
5614                 }
5615                 return buf;
5616         }
5617
5618         public override string GetDeclaration (MemberReference member)
5619         {
5620                 TypeReference r = member as TypeReference;
5621                 if (r != null) {
5622                         return "T:" + GetTypeName (r);
5623                 }
5624                 return base.GetDeclaration (member);
5625         }
5626
5627         protected override string GetConstructorName (MethodReference constructor)
5628         {
5629                 return GetMethodDefinitionName (constructor, "#ctor");
5630         }
5631
5632         protected override string GetMethodName (MethodReference method)
5633         {
5634                 string name = null;
5635                 MethodDefinition methodDef = method as MethodDefinition;
5636                 if (methodDef == null || !DocUtils.IsExplicitlyImplemented (methodDef))
5637                         name = method.Name;
5638                 else {
5639                         TypeReference iface;
5640                         MethodReference ifaceMethod;
5641                         DocUtils.GetInfoForExplicitlyImplementedMethod (methodDef, out iface, out ifaceMethod);
5642                         AddTypeCount = false;
5643                         name = GetTypeName (iface) + "." + ifaceMethod.Name;
5644                         AddTypeCount = true;
5645                 }
5646                 return GetMethodDefinitionName (method, name);
5647         }
5648
5649         private string GetMethodDefinitionName (MethodReference method, string name)
5650         {
5651                 StringBuilder buf = new StringBuilder ();
5652                 buf.Append (GetTypeName (method.DeclaringType));
5653                 buf.Append ('.');
5654                 buf.Append (name.Replace (".", "#"));
5655                 if (method.IsGenericMethod ()) {
5656                         IList<GenericParameter> genArgs = method.GenericParameters;
5657                         if (genArgs.Count > 0)
5658                                 buf.Append ("``").Append (genArgs.Count);
5659                 }
5660                 IList<ParameterDefinition> parameters = method.Parameters;
5661                 try {
5662                         genDeclType   = method.DeclaringType;
5663                         genDeclMethod = method;
5664                         AppendParameters (buf, method.DeclaringType.GenericParameters, parameters);
5665                 }
5666                 finally {
5667                         genDeclType   = null;
5668                         genDeclMethod = null;
5669                 }
5670                 return buf.ToString ();
5671         }
5672
5673         private StringBuilder AppendParameters (StringBuilder buf, IList<GenericParameter> genArgs, IList<ParameterDefinition> parameters)
5674         {
5675                 if (parameters.Count == 0)
5676                         return buf;
5677
5678                 buf.Append ('(');
5679
5680                 AppendParameter (buf, genArgs, parameters [0]);
5681                 for (int i = 1; i < parameters.Count; ++i) {
5682                         buf.Append (',');
5683                         AppendParameter (buf, genArgs, parameters [i]);
5684                 }
5685
5686                 return buf.Append (')');
5687         }
5688
5689         private StringBuilder AppendParameter (StringBuilder buf, IList<GenericParameter> genArgs, ParameterDefinition parameter)
5690         {
5691                 AddTypeCount = false;
5692                 buf.Append (GetTypeName (parameter.ParameterType));
5693                 AddTypeCount = true;
5694                 return buf;
5695         }
5696
5697         protected override string GetPropertyName (PropertyReference property)
5698         {
5699                 string name = null;
5700
5701                 PropertyDefinition propertyDef = property as PropertyDefinition;
5702                 MethodDefinition method = null;
5703                 if (propertyDef != null)
5704                         method = propertyDef.GetMethod ?? propertyDef.SetMethod;
5705                 if (method != null && !DocUtils.IsExplicitlyImplemented (method))
5706                         name = property.Name;
5707                 else {
5708                         TypeReference iface;
5709                         MethodReference ifaceMethod;
5710                         DocUtils.GetInfoForExplicitlyImplementedMethod (method, out iface, out ifaceMethod);
5711                         AddTypeCount = false;
5712                         name = string.Join ("#", new string[]{
5713                                         GetTypeName (iface).Replace (".", "#"),
5714                                         DocUtils.GetMember (property.Name)
5715                         });
5716                         AddTypeCount = true;
5717                 }
5718
5719                 StringBuilder buf = new StringBuilder ();
5720                 buf.Append (GetName (property.DeclaringType));
5721                 buf.Append ('.');
5722                 buf.Append (name);
5723                 IList<ParameterDefinition> parameters = property.Parameters;
5724                 if (parameters.Count > 0) {
5725                         genDeclType = property.DeclaringType;
5726                         buf.Append ('(');
5727                         IList<GenericParameter> genArgs = property.DeclaringType.GenericParameters;
5728                         AppendParameter (buf, genArgs, parameters [0]);
5729                         for (int i = 1; i < parameters.Count; ++i) {
5730                                  buf.Append (',');
5731                                  AppendParameter (buf, genArgs, parameters [i]);
5732                         }
5733                         buf.Append (')');
5734                         genDeclType = null;
5735                 }
5736                 return buf.ToString ();
5737         }
5738
5739         protected override string GetFieldName (FieldReference field)
5740         {
5741                 return string.Format ("{0}.{1}",
5742                         GetName (field.DeclaringType), field.Name);
5743         }
5744
5745         protected override string GetEventName (EventReference e)
5746         {
5747                 return string.Format ("{0}.{1}",
5748                         GetName (e.DeclaringType), e.Name);
5749         }
5750
5751         protected override string GetTypeDeclaration (TypeDefinition type)
5752         {
5753                 string name = GetName (type);
5754                 if (type == null)
5755                         return null;
5756                 return "T:" + name;
5757         }
5758
5759         protected override string GetConstructorDeclaration (MethodDefinition constructor)
5760         {
5761                 string name = GetName (constructor);
5762                 if (name == null)
5763                         return null;
5764                 return "M:" + name;
5765         }
5766
5767         protected override string GetMethodDeclaration (MethodDefinition method)
5768         {
5769                 string name = GetName (method);
5770                 if (name == null)
5771                         return null;
5772                 if (method.Name == "op_Implicit" || method.Name == "op_Explicit") {
5773                         genDeclType = method.DeclaringType;
5774                         genDeclMethod = method;
5775                         name += "~" + GetName (method.ReturnType);
5776                         genDeclType = null;
5777                         genDeclMethod = null;
5778                 }
5779                 return "M:" + name;
5780         }
5781
5782         protected override string GetPropertyDeclaration (PropertyDefinition property)
5783         {
5784                 string name = GetName (property);
5785                 if (name == null)
5786                         return null;
5787                 return "P:" + name;
5788         }
5789
5790         protected override string GetFieldDeclaration (FieldDefinition field)
5791         {
5792                 string name = GetName (field);
5793                 if (name == null)
5794                         return null;
5795                 return "F:" + name;
5796         }
5797
5798         protected override string GetEventDeclaration (EventDefinition e)
5799         {
5800                 string name = GetName (e);
5801                 if (name == null)
5802                         return null;
5803                 return "E:" + name;
5804         }
5805 }
5806
5807 class FileNameMemberFormatter : SlashDocMemberFormatter {
5808         protected override StringBuilder AppendNamespace (StringBuilder buf, TypeReference type)
5809         {
5810                 return buf;
5811         }
5812
5813         protected override char NestedTypeSeparator {
5814                 get {return '+';}
5815         }
5816 }
5817
5818 class ResolvedTypeInfo {
5819         TypeDefinition typeDef;
5820
5821         public ResolvedTypeInfo (TypeReference value) {
5822                 Reference = value;
5823         }
5824
5825         public TypeReference Reference { get; private set; }
5826
5827         public TypeDefinition Definition {
5828                 get {
5829                         if (typeDef == null) {
5830                                 typeDef = Reference.Resolve ();
5831                         }
5832                         return typeDef;
5833                 }
5834         }
5835 }
5836
5837 /// <summary>Formats attribute values. Should return true if it is able to format the value.</summary>
5838 class AttributeValueFormatter {
5839         public virtual bool TryFormatValue (object v, ResolvedTypeInfo type, out string returnvalue)
5840         {
5841                 TypeReference valueType = type.Reference;
5842                 if (v == null) {
5843                         returnvalue = "null";
5844                         return true;
5845                 }
5846                 if (valueType.FullName == "System.Type") {
5847                         var vTypeRef = v as TypeReference;
5848                         if (vTypeRef != null) 
5849                                 returnvalue = "typeof(" + NativeTypeManager.GetTranslatedName (vTypeRef) + ")"; // TODO: drop NS handling
5850                         else
5851                                 returnvalue = "typeof(" + v.ToString () + ")";
5852                         
5853                         return true;
5854                 }
5855                 if (valueType.FullName == "System.String") {
5856                         returnvalue = "\"" + v.ToString () + "\"";
5857                         return true;
5858                 }
5859                 if (valueType.FullName == "System.Char") {
5860                         returnvalue = "'" + v.ToString () + "'";
5861                         return true;
5862                 }
5863                 if (v is Boolean) {
5864                         returnvalue = (bool)v ? "true" : "false";
5865                         return true;
5866                 }
5867
5868                 TypeDefinition valueDef = type.Definition;
5869                 if (valueDef == null || !valueDef.IsEnum) {
5870                         returnvalue = v.ToString ();
5871                         return true;
5872                 }
5873
5874                 string typename = MDocUpdater.GetDocTypeFullName (valueType);
5875                 var values = MDocUpdater.GetEnumerationValues (valueDef);
5876                 long c = MDocUpdater.ToInt64 (v);
5877                 if (values.ContainsKey (c)) {
5878                         returnvalue = typename + "." + values [c];
5879                         return true;
5880                 }
5881
5882                 returnvalue = null;
5883                 return false;
5884         }
5885 }
5886
5887 /// <summary>The final value formatter in the pipeline ... if no other formatter formats the value,
5888 /// then this one will serve as the default implementation.</summary>
5889 class DefaultAttributeValueFormatter : AttributeValueFormatter {
5890         public override bool TryFormatValue (object v, ResolvedTypeInfo type, out string returnvalue)
5891         {
5892                 returnvalue = "(" + MDocUpdater.GetDocTypeFullName (type.Reference) + ") " + v.ToString ();
5893                 return true;
5894         }
5895 }
5896
5897 /// <summary>Flags enum formatter that assumes powers of two values.</summary>
5898 /// <remarks>As described here: https://msdn.microsoft.com/en-us/library/vstudio/ms229062(v=vs.100).aspx</remarks>
5899 class StandardFlagsEnumFormatter : AttributeValueFormatter {
5900         public override bool TryFormatValue (object v, ResolvedTypeInfo type, out string returnvalue)
5901         {
5902                 TypeReference valueType = type.Reference;
5903                 TypeDefinition valueDef = type.Definition;
5904                 if (valueDef.CustomAttributes.Any (ca => ca.AttributeType.FullName == "System.FlagsAttribute")) {
5905
5906                         string typename = MDocUpdater.GetDocTypeFullName (valueType);
5907                         var values = MDocUpdater.GetEnumerationValues (valueDef);
5908                         long c = MDocUpdater.ToInt64 (v);
5909                         returnvalue = string.Join (" | ",
5910                                 (from i in values.Keys
5911                                  where (c & i) == i && i != 0
5912                                  select typename + "." + values [i])
5913                                 .DefaultIfEmpty (c.ToString ()).ToArray ());
5914                         
5915                         return true;
5916                 }
5917
5918                 returnvalue = null;
5919                 return false;
5920         }
5921 }
5922
5923 /// <summary>A custom formatter for the ObjCRuntime.Platform enumeration.</summary>
5924 class ApplePlatformEnumFormatter : AttributeValueFormatter {
5925         public override bool TryFormatValue (object v, ResolvedTypeInfo type, out string returnvalue)
5926         {
5927                 TypeReference valueType = type.Reference;
5928                 string typename = MDocUpdater.GetDocTypeFullName (valueType);
5929                 TypeDefinition valueDef = type.Definition;
5930                 if (typename.Contains ("ObjCRuntime.Platform") && valueDef.CustomAttributes.Any (ca => ca.AttributeType.FullName == "System.FlagsAttribute")) {
5931
5932                         var values = MDocUpdater.GetEnumerationValues (valueDef);
5933                         long c = MDocUpdater.ToInt64 (v);
5934
5935                         returnvalue = Format (c, values, typename);
5936                         return true;
5937                 }
5938
5939                 returnvalue = null;
5940                 return false;
5941         }
5942
5943         string Format (long c, IDictionary<long, string> values, string typename)
5944         {
5945                 int iosarch, iosmajor, iosminor, iossubminor;
5946                 int macarch, macmajor, macminor, macsubminor;
5947                 GetEncodingiOS (c, out iosarch, out iosmajor, out iosminor, out iossubminor);
5948                 GetEncodingMac ((ulong)c, out macarch, out macmajor, out macminor, out macsubminor);
5949
5950                 if (iosmajor == 0 & iosminor == 0 && iossubminor == 0) {
5951                         return FormatValues ("Mac", macarch, macmajor, macminor, macsubminor);
5952                 }
5953
5954                 if (macmajor == 0 & macminor == 0 && macsubminor == 0) {
5955                         return FormatValues ("iOS", iosarch, iosmajor, iosminor, iossubminor);
5956                 }
5957
5958                 return string.Format ("(Platform){0}", c);
5959         }
5960
5961         string FormatValues (string plat, int arch, int major, int minor, int subminor) 
5962         {
5963                 string archstring = "";
5964                 switch (arch) {
5965                 case 1:
5966                         archstring = "32";
5967                         break;
5968                 case 2:
5969                         archstring = "64";
5970                         break;
5971                 }
5972                 return string.Format ("Platform.{4}_{0}_{1}{2} | Platform.{4}_Arch{3}",
5973                         major,
5974                         minor,
5975                         subminor == 0 ? "" : "_" + subminor.ToString (),
5976                         archstring,
5977                         plat
5978                 );
5979         }
5980
5981         void GetEncodingiOS (long entireLong, out int archindex, out int major, out int minor, out int subminor)
5982         {
5983                 long lowerBits = entireLong & 0xffffffff; 
5984                 int lowerBitsAsInt = (int) lowerBits;
5985                 GetEncoding (lowerBitsAsInt, out archindex, out major, out minor, out subminor);
5986         }
5987
5988         void GetEncodingMac (ulong entireLong, out int archindex, out int major, out int minor, out int subminor)
5989         {
5990                 ulong higherBits = entireLong & 0xffffffff00000000; 
5991                 int higherBitsAsInt = (int) ((higherBits) >> 32);
5992                 GetEncoding (higherBitsAsInt, out archindex, out major, out minor, out subminor);
5993         }
5994
5995         void GetEncoding (Int32 encodedBits, out int archindex, out int major, out int minor, out int subminor)
5996         {
5997                 // format is AAJJNNSS
5998                 archindex = (int)((encodedBits & 0xFF000000) >> 24);
5999                 major = (int)((encodedBits & 0x00FF0000) >> 16);
6000                 minor = (int)((encodedBits & 0x0000FF00) >> 8);
6001                 subminor = (int)((encodedBits & 0x000000FF) >> 0);
6002         }
6003 }
6004 }