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