1 // Updater program for syncing Mono's ECMA-style documentation files
3 // By Joshua Tauberer <tauberer@for.net>
6 using System.Collections;
7 using System.Collections.Generic;
8 using System.Diagnostics;
9 using System.Globalization;
14 using System.Xml.XPath;
19 using MyXmlNodeList = System.Collections.Generic.List<System.Xml.XmlNode>;
20 using StringList = System.Collections.Generic.List<string>;
21 using StringToStringMap = System.Collections.Generic.Dictionary<string, string>;
22 using StringToXmlNodeMap = System.Collections.Generic.Dictionary<string, System.Xml.XmlNode>;
24 namespace Mono.Documentation {
26 class MDocUpdater : MDocCommand
29 List<AssemblyDefinition> assemblies;
30 readonly DefaultAssemblyResolver assemblyResolver = new DefaultAssemblyResolver();
34 bool no_assembly_versions, ignore_missing_types;
35 ExceptionLocations? exceptions;
37 internal int additions = 0, deletions = 0;
39 List<DocumentationImporter> importers = new List<DocumentationImporter> ();
41 DocumentationEnumerator docEnum;
45 static readonly MemberFormatter docTypeFormatter = new DocTypeMemberFormatter ();
46 static readonly MemberFormatter filenameFormatter = new FileNameMemberFormatter ();
48 static MemberFormatter[] typeFormatters = new MemberFormatter[]{
49 new CSharpMemberFormatter (),
50 new ILMemberFormatter (),
53 static MemberFormatter[] memberFormatters = new MemberFormatter[]{
54 new CSharpFullMemberFormatter (),
55 new ILFullMemberFormatter (),
58 internal static readonly MemberFormatter slashdocFormatter = new SlashDocMemberFormatter ();
60 MyXmlNodeList extensionMethods = new MyXmlNodeList ();
62 public override void Run (IEnumerable<string> args)
64 show_exceptions = DebugOutput;
66 var types = new List<string> ();
67 var p = new OptionSet () {
69 "Delete removed members from the XML files.",
70 v => delete = v != null },
72 "Document potential exceptions that members can generate. {SOURCES} " +
73 "is a comma-separated list of:\n" +
74 " asm Method calls in same assembly\n" +
75 " depasm Method calls in dependent assemblies\n" +
76 " all Record all possible exceptions\n" +
77 " added Modifier; only create <exception/>s\n" +
78 " for NEW types/members\n" +
79 "If nothing is specified, then only exceptions from the member will " +
81 v => exceptions = ParseExceptionLocations (v) },
83 "Specify a {FLAG} to alter behavior. See later -f* options for available flags.",
86 case "ignore-missing-types":
87 ignore_missing_types = true;
89 case "no-assembly-versions":
90 no_assembly_versions = true;
93 throw new Exception ("Unsupported flag `" + v + "'.");
96 { "fignore-missing-types",
97 "Do not report an error if a --type=TYPE type\nwas not found.",
98 v => ignore_missing_types = v != null },
99 { "fno-assembly-versions",
100 "Do not generate //AssemblyVersion elements.",
101 v => no_assembly_versions = v != null },
103 "Import documentation from {FILE}.",
104 v => AddImporter (v) },
106 "Check for assembly references in {DIRECTORY}.",
107 v => assemblyResolver.AddSearchDirectory (v) },
109 "Ignored for compatibility with update-ecma-xml.",
112 "Root {DIRECTORY} to generate/update documentation.",
115 "Search for dependent assemblies in the directory containing {ASSEMBLY}.\n" +
116 "(Equivalent to '-L `dirname ASSEMBLY`'.)",
117 v => assemblyResolver.AddSearchDirectory (Path.GetDirectoryName (v)) },
119 "Manually specify the assembly {VERSION} that new members were added in.",
122 "Only update documentation for {TYPE}.",
123 v => types.Add (v) },
125 var assemblies = Parse (p, args, "update",
126 "[OPTIONS]+ ASSEMBLIES",
127 "Create or update documentation from ASSEMBLIES.");
128 if (assemblies == null)
130 if (assemblies.Count == 0)
131 Error ("No assemblies specified.");
133 foreach (var dir in assemblies
134 .Where (a => a.Contains (Path.DirectorySeparatorChar))
135 .Select (a => Path.GetDirectoryName (a)))
136 assemblyResolver.AddSearchDirectory (dir);
138 // PARSE BASIC OPTIONS AND LOAD THE ASSEMBLY TO DOCUMENT
141 throw new InvalidOperationException("The --out option is required.");
143 this.assemblies = assemblies.Select (a => LoadAssembly (a)).ToList ();
145 docEnum = docEnum ?? new DocumentationEnumerator ();
147 // PERFORM THE UPDATES
149 if (types.Count > 0) {
151 DoUpdateTypes (srcPath, types, srcPath);
154 else if (opts.@namespace != null)
155 DoUpdateNS (opts.@namespace, Path.Combine (opts.path, opts.@namespace),
156 Path.Combine (dest_dir, opts.@namespace));
159 DoUpdateAssemblies (srcPath, srcPath);
161 Console.WriteLine("Members Added: {0}, Members Deleted: {1}", additions, deletions);
164 void AddImporter (string path)
167 XmlReader r = new XmlTextReader (path);
169 while (r.NodeType != XmlNodeType.Element) {
171 Error ("Unable to read XML file: {0}.", path);
173 if (r.LocalName == "doc") {
174 importers.Add (new MsxdocDocumentationImporter (path));
176 else if (r.LocalName == "Libraries") {
177 var ecmadocs = new XmlTextReader (path);
178 docEnum = new EcmaDocumentationEnumerator (this, ecmadocs);
179 importers.Add (new EcmaDocumentationImporter (ecmadocs));
182 Error ("Unsupported XML format within {0}.", path);
185 } catch (Exception e) {
186 Environment.ExitCode = 1;
187 Error ("Could not load XML file: {0}.", e.Message);
191 static ExceptionLocations ParseExceptionLocations (string s)
193 ExceptionLocations loc = ExceptionLocations.Member;
196 foreach (var type in s.Split (',')) {
198 case "added": loc |= ExceptionLocations.AddedMembers; break;
199 case "all": loc |= ExceptionLocations.Assembly | ExceptionLocations.DependentAssemblies; break;
200 case "asm": loc |= ExceptionLocations.Assembly; break;
201 case "depasm": loc |= ExceptionLocations.DependentAssemblies; break;
202 default: throw new NotSupportedException ("Unsupported --exceptions value: " + type);
208 internal void Warning (string format, params object[] args)
210 Message (TraceLevel.Warning, "mdoc: " + format, args);
213 private AssemblyDefinition LoadAssembly (string name)
215 AssemblyDefinition assembly = null;
217 assembly = AssemblyDefinition.ReadAssembly (name, new ReaderParameters { AssemblyResolver = assemblyResolver });
218 } catch (System.IO.FileNotFoundException) { }
220 if (assembly == null)
221 throw new InvalidOperationException("Assembly " + name + " not found.");
226 private static void WriteXml(XmlElement element, System.IO.TextWriter output) {
227 OrderTypeAttributes (element);
228 XmlTextWriter writer = new XmlTextWriter(output);
229 writer.Formatting = Formatting.Indented;
230 writer.Indentation = 2;
231 writer.IndentChar = ' ';
232 element.WriteTo(writer);
236 private static void WriteFile (string filename, FileMode mode, Action<TextWriter> action)
238 Action<string> creator = file => {
239 using (var writer = OpenWrite (file, mode))
243 MdocFile.UpdateFile (filename, creator);
246 private static void OrderTypeAttributes (XmlElement e)
248 foreach (XmlElement type in e.SelectNodes ("//Type")) {
249 OrderTypeAttributes (type.Attributes);
253 static readonly string[] TypeAttributeOrder = {
254 "Name", "FullName", "FullNameSP", "Maintainer"
257 private static void OrderTypeAttributes (XmlAttributeCollection c)
259 XmlAttribute[] attrs = new XmlAttribute [TypeAttributeOrder.Length];
260 for (int i = 0; i < c.Count; ++i) {
261 XmlAttribute a = c [i];
262 for (int j = 0; j < TypeAttributeOrder.Length; ++j) {
263 if (a.Name == TypeAttributeOrder [j]) {
269 for (int i = attrs.Length-1; i >= 0; --i) {
270 XmlAttribute n = attrs [i];
273 XmlAttribute r = null;
274 for (int j = i+1; j < attrs.Length; ++j) {
275 if (attrs [j] != null) {
283 c.InsertBefore (n, r);
287 private XmlDocument CreateIndexStub()
289 XmlDocument index = new XmlDocument();
291 XmlElement index_root = index.CreateElement("Overview");
292 index.AppendChild(index_root);
294 if (assemblies.Count == 0)
295 throw new Exception ("No assembly");
297 XmlElement index_assemblies = index.CreateElement("Assemblies");
298 index_root.AppendChild(index_assemblies);
300 XmlElement index_remarks = index.CreateElement("Remarks");
301 index_remarks.InnerText = "To be added.";
302 index_root.AppendChild(index_remarks);
304 XmlElement index_copyright = index.CreateElement("Copyright");
305 index_copyright.InnerText = "To be added.";
306 index_root.AppendChild(index_copyright);
308 XmlElement index_types = index.CreateElement("Types");
309 index_root.AppendChild(index_types);
314 private static void WriteNamespaceStub(string ns, string outdir) {
315 XmlDocument index = new XmlDocument();
317 XmlElement index_root = index.CreateElement("Namespace");
318 index.AppendChild(index_root);
320 index_root.SetAttribute("Name", ns);
322 XmlElement index_docs = index.CreateElement("Docs");
323 index_root.AppendChild(index_docs);
325 XmlElement index_summary = index.CreateElement("summary");
326 index_summary.InnerText = "To be added.";
327 index_docs.AppendChild(index_summary);
329 XmlElement index_remarks = index.CreateElement("remarks");
330 index_remarks.InnerText = "To be added.";
331 index_docs.AppendChild(index_remarks);
333 WriteFile (outdir + "/ns-" + ns + ".xml", FileMode.CreateNew,
334 writer => WriteXml (index.DocumentElement, writer));
337 public void DoUpdateTypes (string basepath, List<string> typenames, string dest)
339 var index = CreateIndexForTypes (dest);
341 var found = new HashSet<string> ();
342 foreach (AssemblyDefinition assembly in assemblies) {
343 foreach (TypeDefinition type in docEnum.GetDocumentationTypes (assembly, typenames)) {
344 string relpath = DoUpdateType (type, basepath, dest);
348 found.Add (type.FullName);
353 index.Add (assembly);
361 if (ignore_missing_types)
364 var notFound = from n in typenames where !found.Contains (n) select n;
366 throw new InvalidOperationException("Type(s) not found: " + string.Join (", ", notFound.ToArray ()));
369 class IndexForTypes {
375 XmlElement index_types;
376 XmlElement index_assemblies;
378 public IndexForTypes (MDocUpdater app, string indexFile, XmlDocument index)
381 this.indexFile = indexFile;
384 index_types = WriteElement (index.DocumentElement, "Types");
385 index_assemblies = WriteElement (index.DocumentElement, "Assemblies");
388 public void Add (AssemblyDefinition assembly)
390 if (index_assemblies.SelectSingleNode ("Assembly[@Name='" + assembly.Name.Name + "']") != null)
393 app.AddIndexAssembly (assembly, index_assemblies);
396 public void Add (TypeDefinition type)
398 app.AddIndexType (type, index_types);
403 SortIndexEntries (index_types);
404 WriteFile (indexFile, FileMode.Create,
405 writer => WriteXml (index.DocumentElement, writer));
409 IndexForTypes CreateIndexForTypes (string dest)
411 string indexFile = Path.Combine (dest, "index.xml");
412 if (File.Exists (indexFile))
414 return new IndexForTypes (this, indexFile, CreateIndexStub ());
417 public string DoUpdateType (TypeDefinition type, string basepath, string dest)
419 if (type.Namespace == null)
420 Warning ("warning: The type `{0}' is in the root namespace. This may cause problems with display within monodoc.",
422 if (!IsPublic (type))
425 // Must get the A+B form of the type name.
426 string typename = GetTypeFileName(type);
428 string reltypefile = DocUtils.PathCombine (DocUtils.GetNamespace (type), typename + ".xml");
429 string typefile = Path.Combine (basepath, reltypefile);
430 System.IO.FileInfo file = new System.IO.FileInfo(typefile);
432 string output = null;
435 } else if (dest == "-") {
438 output = Path.Combine (dest, reltypefile);
443 XmlDocument basefile = new XmlDocument();
445 basefile.Load(typefile);
446 } catch (Exception e) {
447 throw new InvalidOperationException("Error loading " + typefile + ": " + e.Message, e);
450 DoUpdateType2("Updating", basefile, type, output, false);
453 XmlElement td = StubType(type, output);
457 System.IO.DirectoryInfo dir = new System.IO.DirectoryInfo (DocUtils.PathCombine (dest, type.Namespace));
460 Console.WriteLine("Namespace Directory Created: " + type.Namespace);
466 public void DoUpdateNS (string ns, string nspath, string outpath)
468 Dictionary<TypeDefinition, object> seenTypes = new Dictionary<TypeDefinition,object> ();
469 AssemblyDefinition assembly = assemblies [0];
471 foreach (System.IO.FileInfo file in new System.IO.DirectoryInfo(nspath).GetFiles("*.xml")) {
472 XmlDocument basefile = new XmlDocument();
473 string typefile = Path.Combine(nspath, file.Name);
475 basefile.Load(typefile);
476 } catch (Exception e) {
477 throw new InvalidOperationException("Error loading " + typefile + ": " + e.Message, e);
481 GetTypeFileName (basefile.SelectSingleNode("Type/@FullName").InnerText);
482 TypeDefinition type = assembly.GetType(typename);
484 Warning ("Type no longer in assembly: " + typename);
488 seenTypes[type] = seenTypes;
489 DoUpdateType2("Updating", basefile, type, Path.Combine(outpath, file.Name), false);
492 // Stub types not in the directory
493 foreach (TypeDefinition type in docEnum.GetDocumentationTypes (assembly, null)) {
494 if (type.Namespace != ns || seenTypes.ContainsKey(type))
497 XmlElement td = StubType(type, Path.Combine(outpath, GetTypeFileName(type) + ".xml"));
498 if (td == null) continue;
502 private static string GetTypeFileName (TypeReference type)
504 return filenameFormatter.GetName (type);
507 public static string GetTypeFileName (string typename)
509 StringBuilder filename = new StringBuilder (typename.Length);
513 for (int i = 0; i < typename.Length; ++i) {
514 char c = typename [i];
523 filename.Append ('`').Append ((numArgs+1).ToString());
538 return filename.ToString ();
541 private void AddIndexAssembly (AssemblyDefinition assembly, XmlElement parent)
543 XmlElement index_assembly = parent.OwnerDocument.CreateElement("Assembly");
544 index_assembly.SetAttribute ("Name", assembly.Name.Name);
545 index_assembly.SetAttribute ("Version", assembly.Name.Version.ToString());
547 AssemblyNameDefinition name = assembly.Name;
548 if (name.HasPublicKey) {
549 XmlElement pubkey = parent.OwnerDocument.CreateElement ("AssemblyPublicKey");
550 var key = new StringBuilder (name.PublicKey.Length*3 + 2);
552 foreach (byte b in name.PublicKey)
553 key.AppendFormat ("{0,2:x2} ", b);
555 pubkey.InnerText = key.ToString ();
556 index_assembly.AppendChild (pubkey);
559 if (!string.IsNullOrEmpty (name.Culture)) {
560 XmlElement culture = parent.OwnerDocument.CreateElement ("AssemblyCulture");
561 culture.InnerText = name.Culture;
562 index_assembly.AppendChild (culture);
565 MakeAttributes (index_assembly, GetCustomAttributes (assembly.CustomAttributes, ""));
566 parent.AppendChild(index_assembly);
569 private void AddIndexType (TypeDefinition type, XmlElement index_types)
571 string typename = GetTypeFileName(type);
573 // Add namespace and type nodes into the index file as needed
574 string ns = DocUtils.GetNamespace (type);
575 XmlElement nsnode = (XmlElement) index_types.SelectSingleNode ("Namespace[@Name='" + ns + "']");
576 if (nsnode == null) {
577 nsnode = index_types.OwnerDocument.CreateElement("Namespace");
578 nsnode.SetAttribute ("Name", ns);
579 index_types.AppendChild (nsnode);
581 string doc_typename = GetDocTypeName (type);
582 XmlElement typenode = (XmlElement) nsnode.SelectSingleNode ("Type[@Name='" + typename + "']");
583 if (typenode == null) {
584 typenode = index_types.OwnerDocument.CreateElement ("Type");
585 typenode.SetAttribute ("Name", typename);
586 nsnode.AppendChild (typenode);
588 if (typename != doc_typename)
589 typenode.SetAttribute("DisplayName", doc_typename);
591 typenode.RemoveAttribute("DisplayName");
593 typenode.SetAttribute ("Kind", GetTypeKind (type));
596 private void DoUpdateAssemblies (string source, string dest)
598 string indexfile = dest + "/index.xml";
600 if (System.IO.File.Exists(indexfile)) {
601 index = new XmlDocument();
602 index.Load(indexfile);
605 ClearElement(index.DocumentElement, "Assembly");
606 ClearElement(index.DocumentElement, "Attributes");
608 index = CreateIndexStub();
611 string defaultTitle = "Untitled";
612 if (assemblies.Count == 1)
613 defaultTitle = assemblies[0].Name.Name;
614 WriteElementInitialText(index.DocumentElement, "Title", defaultTitle);
616 XmlElement index_types = WriteElement(index.DocumentElement, "Types");
617 XmlElement index_assemblies = WriteElement(index.DocumentElement, "Assemblies");
618 index_assemblies.RemoveAll ();
621 HashSet<string> goodfiles = new HashSet<string> ();
623 foreach (AssemblyDefinition assm in assemblies) {
624 AddIndexAssembly (assm, index_assemblies);
625 DoUpdateAssembly (assm, index_types, source, dest, goodfiles);
628 SortIndexEntries (index_types);
630 CleanupFiles (dest, goodfiles);
631 CleanupIndexTypes (index_types, goodfiles);
632 CleanupExtensions (index_types);
634 WriteFile (indexfile, FileMode.Create,
635 writer => WriteXml(index.DocumentElement, writer));
638 private static char[] InvalidFilenameChars = {'\\', '/', ':', '*', '?', '"', '<', '>', '|'};
640 private void DoUpdateAssembly (AssemblyDefinition assembly, XmlElement index_types, string source, string dest, HashSet<string> goodfiles)
642 foreach (TypeDefinition type in docEnum.GetDocumentationTypes (assembly, null)) {
643 string typename = GetTypeFileName(type);
644 if (!IsPublic (type) || typename.IndexOfAny (InvalidFilenameChars) >= 0)
647 string reltypepath = DoUpdateType (type, source, dest);
648 if (reltypepath == null)
651 // Add namespace and type nodes into the index file as needed
652 AddIndexType (type, index_types);
654 // Ensure the namespace index file exists
655 string onsdoc = DocUtils.PathCombine (dest, type.Namespace + ".xml");
656 string nsdoc = DocUtils.PathCombine (dest, "ns-" + type.Namespace + ".xml");
657 if (File.Exists (onsdoc)) {
658 File.Move (onsdoc, nsdoc);
661 if (!File.Exists (nsdoc)) {
662 Console.WriteLine("New Namespace File: " + type.Namespace);
663 WriteNamespaceStub(type.Namespace, dest);
666 goodfiles.Add (reltypepath);
670 private static void SortIndexEntries (XmlElement indexTypes)
672 XmlNodeList namespaces = indexTypes.SelectNodes ("Namespace");
673 XmlNodeComparer c = new AttributeNameComparer ();
674 SortXmlNodes (indexTypes, namespaces, c);
676 for (int i = 0; i < namespaces.Count; ++i)
677 SortXmlNodes (namespaces [i], namespaces [i].SelectNodes ("Type"), c);
680 private static void SortXmlNodes (XmlNode parent, XmlNodeList children, XmlNodeComparer comparer)
682 MyXmlNodeList l = new MyXmlNodeList (children.Count);
683 for (int i = 0; i < children.Count; ++i)
684 l.Add (children [i]);
686 for (int i = l.Count - 1; i > 0; --i) {
687 parent.InsertBefore (parent.RemoveChild ((XmlNode) l [i-1]), (XmlNode) l [i]);
691 abstract class XmlNodeComparer : IComparer, IComparer<XmlNode>
693 public abstract int Compare (XmlNode x, XmlNode y);
695 public int Compare (object x, object y)
697 return Compare ((XmlNode) x, (XmlNode) y);
701 class AttributeNameComparer : XmlNodeComparer {
704 public AttributeNameComparer ()
709 public AttributeNameComparer (string attribute)
711 this.attribute = attribute;
714 public override int Compare (XmlNode x, XmlNode y)
716 return x.Attributes [attribute].Value.CompareTo (y.Attributes [attribute].Value);
720 class VersionComparer : XmlNodeComparer {
721 public override int Compare (XmlNode x, XmlNode y)
723 // Some of the existing docs use e.g. 1.0.x.x, which Version doesn't like.
724 string a = GetVersion (x.InnerText);
725 string b = GetVersion (y.InnerText);
726 return new Version (a).CompareTo (new Version (b));
729 static string GetVersion (string v)
731 int n = v.IndexOf ("x");
734 return v.Substring (0, n-1);
738 private static string GetTypeKind (TypeDefinition type)
741 return "Enumeration";
742 if (type.IsValueType)
744 if (type.IsInterface)
746 if (DocUtils.IsDelegate (type))
748 if (type.IsClass || type.FullName == "System.Enum") // FIXME
750 throw new ArgumentException ("Unknown kind for type: " + type.FullName);
753 private static bool IsPublic (TypeDefinition type)
755 TypeDefinition decl = type;
756 while (decl != null) {
757 if (!(decl.IsPublic || decl.IsNestedPublic)) {
760 decl = (TypeDefinition) decl.DeclaringType;
765 private void CleanupFiles (string dest, HashSet<string> goodfiles)
767 // Look for files that no longer correspond to types
768 foreach (System.IO.DirectoryInfo nsdir in new System.IO.DirectoryInfo(dest).GetDirectories("*")) {
769 foreach (System.IO.FileInfo typefile in nsdir.GetFiles("*.xml")) {
770 string relTypeFile = Path.Combine(nsdir.Name, typefile.Name);
771 if (!goodfiles.Contains (relTypeFile)) {
772 XmlDocument doc = new XmlDocument ();
773 doc.Load (typefile.FullName);
774 XmlElement e = doc.SelectSingleNode("/Type") as XmlElement;
775 if (UpdateAssemblyVersions(e, GetAssemblyVersions(), false)) {
776 using (TextWriter writer = OpenWrite (typefile.FullName, FileMode.Truncate))
777 WriteXml(doc.DocumentElement, writer);
778 goodfiles.Add (relTypeFile);
781 string newname = typefile.FullName + ".remove";
782 try { System.IO.File.Delete(newname); } catch (Exception) { }
783 try { typefile.MoveTo(newname); } catch (Exception) { }
784 Console.WriteLine("Class no longer present; file renamed: " + Path.Combine(nsdir.Name, typefile.Name));
790 private static TextWriter OpenWrite (string path, FileMode mode)
792 var w = new StreamWriter (
793 new FileStream (path, mode),
794 new UTF8Encoding (false)
800 private string[] GetAssemblyVersions ()
802 return (from a in assemblies select GetAssemblyVersion (a)).ToArray ();
805 private static void CleanupIndexTypes (XmlElement index_types, HashSet<string> goodfiles)
807 // Look for type nodes that no longer correspond to types
808 MyXmlNodeList remove = new MyXmlNodeList ();
809 foreach (XmlElement typenode in index_types.SelectNodes("Namespace/Type")) {
810 string fulltypename = Path.Combine (((XmlElement)typenode.ParentNode).GetAttribute("Name"), typenode.GetAttribute("Name") + ".xml");
811 if (!goodfiles.Contains (fulltypename)) {
812 remove.Add (typenode);
815 foreach (XmlNode n in remove)
816 n.ParentNode.RemoveChild (n);
819 private void CleanupExtensions (XmlElement index_types)
821 XmlNode e = index_types.SelectSingleNode ("/Overview/ExtensionMethods");
822 if (extensionMethods.Count == 0) {
825 index_types.SelectSingleNode ("/Overview").RemoveChild (e);
829 e = index_types.OwnerDocument.CreateElement ("ExtensionMethods");
830 index_types.SelectSingleNode ("/Overview").AppendChild (e);
834 extensionMethods.Sort (DefaultExtensionMethodComparer);
835 foreach (XmlNode m in extensionMethods) {
836 e.AppendChild (index_types.OwnerDocument.ImportNode (m, true));
840 class ExtensionMethodComparer : XmlNodeComparer {
841 public override int Compare (XmlNode x, XmlNode y)
843 XmlNode xLink = x.SelectSingleNode ("Member/Link");
844 XmlNode yLink = y.SelectSingleNode ("Member/Link");
846 int n = xLink.Attributes ["Type"].Value.CompareTo (
847 yLink.Attributes ["Type"].Value);
850 n = xLink.Attributes ["Member"].Value.CompareTo (
851 yLink.Attributes ["Member"].Value);
852 if (n == 0 && !object.ReferenceEquals (x, y))
853 throw new InvalidOperationException ("Duplicate extension method found!");
858 static readonly XmlNodeComparer DefaultExtensionMethodComparer = new ExtensionMethodComparer ();
860 public void DoUpdateType2 (string message, XmlDocument basefile, TypeDefinition type, string output, bool insertSince)
862 Console.WriteLine(message + ": " + type.FullName);
864 StringToXmlNodeMap seenmembers = new StringToXmlNodeMap ();
866 // Update type metadata
867 UpdateType(basefile.DocumentElement, type);
869 // Update existing members. Delete member nodes that no longer should be there,
870 // and remember what members are already documented so we don't add them again.
872 MyXmlNodeList todelete = new MyXmlNodeList ();
873 foreach (DocsNodeInfo info in docEnum.GetDocumentationMembers (basefile, type)) {
874 XmlElement oldmember = info.Node;
875 MemberReference oldmember2 = info.Member;
876 string sig = oldmember2 != null ? memberFormatters [0].GetDeclaration (oldmember2) : null;
878 // Interface implementations and overrides are deleted from the docs
879 // unless the overrides option is given.
880 if (oldmember2 != null && sig == null)
883 // Deleted (or signature changed)
884 if (oldmember2 == null) {
885 if (UpdateAssemblyVersions (oldmember, new string[]{ GetAssemblyVersion (type.Module.Assembly) }, false))
887 DeleteMember ("Member Removed", output, oldmember, todelete);
892 if (seenmembers.ContainsKey (sig)) {
893 if (object.ReferenceEquals (oldmember, seenmembers [sig])) {
894 // ignore, already seen
896 else if (DefaultMemberComparer.Compare (oldmember, seenmembers [sig]) == 0)
897 DeleteMember ("Duplicate Member Found", output, oldmember, todelete);
899 Warning ("TODO: found a duplicate member '{0}', but it's not identical to the prior member found!", sig);
903 // Update signature information
906 seenmembers.Add (sig, oldmember);
908 foreach (XmlElement oldmember in todelete)
909 oldmember.ParentNode.RemoveChild (oldmember);
912 if (!DocUtils.IsDelegate (type)) {
913 XmlNode members = WriteElement (basefile.DocumentElement, "Members");
914 foreach (MemberReference m in type.GetMembers()) {
915 if (m is TypeDefinition) continue;
917 string sig = memberFormatters [0].GetDeclaration (m);
918 if (sig == null) continue;
919 if (seenmembers.ContainsKey(sig)) continue;
921 XmlElement mm = MakeMember(basefile, new DocsNodeInfo (null, m));
922 if (mm == null) continue;
923 members.AppendChild( mm );
925 Console.WriteLine("Member Added: " + mm.SelectSingleNode("MemberSignature/@Value").InnerText);
930 // Import code snippets from files
931 foreach (XmlNode code in basefile.GetElementsByTagName("code")) {
932 if (!(code is XmlElement)) continue;
933 string file = ((XmlElement)code).GetAttribute("src");
934 string lang = ((XmlElement)code).GetAttribute("lang");
936 string src = GetCodeSource (lang, Path.Combine (srcPath, file));
938 code.InnerText = src;
942 if (insertSince && since != null) {
943 XmlNode docs = basefile.DocumentElement.SelectSingleNode("Docs");
944 docs.AppendChild (CreateSinceNode (basefile));
948 XmlElement d = basefile.DocumentElement ["Docs"];
949 XmlElement m = basefile.DocumentElement ["Members"];
950 if (d != null && m != null)
951 basefile.DocumentElement.InsertBefore (
952 basefile.DocumentElement.RemoveChild (d), m);
957 WriteXml(basefile.DocumentElement, Console.Out);
959 FileInfo file = new FileInfo (output);
960 if (!file.Directory.Exists) {
961 Console.WriteLine("Namespace Directory Created: " + type.Namespace);
962 file.Directory.Create ();
964 WriteFile (output, FileMode.Create,
965 writer => WriteXml(basefile.DocumentElement, writer));
969 private string GetCodeSource (string lang, string file)
972 if (lang == "C#" && (anchorStart = file.IndexOf (".cs#")) >= 0) {
973 // Grab the specified region
974 string region = "#region " + file.Substring (anchorStart + 4);
975 file = file.Substring (0, anchorStart + 3);
977 using (StreamReader reader = new StreamReader (file)) {
979 StringBuilder src = new StringBuilder ();
981 while ((line = reader.ReadLine ()) != null) {
982 if (line.Trim() == region) {
983 indent = line.IndexOf (region);
986 if (indent >= 0 && line.Trim().StartsWith ("#endregion")) {
991 (line.Length > 0 ? line.Substring (indent) : string.Empty) +
994 return src.ToString ();
996 } catch (Exception e) {
997 Warning ("Could not load <code/> file '{0}' region '{1}': {2}",
998 file, region, show_exceptions ? e.ToString () : e.Message);
1003 using (StreamReader reader = new StreamReader (file))
1004 return reader.ReadToEnd ();
1005 } catch (Exception e) {
1006 Warning ("Could not load <code/> file '" + file + "': " + e.Message);
1011 void DeleteMember (string reason, string output, XmlNode member, MyXmlNodeList todelete)
1013 string format = output != null
1014 ? "{0}: File='{1}'; Signature='{4}'"
1015 : "{0}: XPath='/Type[@FullName=\"{2}\"]/Members/Member[@MemberName=\"{3}\"]'; Signature='{4}'";
1019 member.OwnerDocument.DocumentElement.GetAttribute ("FullName"),
1020 member.Attributes ["MemberName"].Value,
1021 member.SelectSingleNode ("MemberSignature[@Language='C#']/@Value").Value);
1022 if (!delete && MemberDocsHaveUserContent (member)) {
1023 Warning ("Member deletions must be enabled with the --delete option.");
1025 todelete.Add (member);
1030 class MemberComparer : XmlNodeComparer {
1031 public override int Compare (XmlNode x, XmlNode y)
1034 string xMemberName = x.Attributes ["MemberName"].Value;
1035 string yMemberName = y.Attributes ["MemberName"].Value;
1037 // generic methods *end* with '>'
1038 // it's possible for explicitly implemented generic interfaces to
1039 // contain <...> without being a generic method
1040 if ((!xMemberName.EndsWith (">") || !yMemberName.EndsWith (">")) &&
1041 (r = xMemberName.CompareTo (yMemberName)) != 0)
1045 if ((lt = xMemberName.IndexOf ("<")) >= 0)
1046 xMemberName = xMemberName.Substring (0, lt);
1047 if ((lt = yMemberName.IndexOf ("<")) >= 0)
1048 yMemberName = yMemberName.Substring (0, lt);
1049 if ((r = xMemberName.CompareTo (yMemberName)) != 0)
1052 // if @MemberName matches, then it's either two different types of
1053 // members sharing the same name, e.g. field & property, or it's an
1054 // overloaded method.
1055 // for different type, sort based on MemberType value.
1056 r = x.SelectSingleNode ("MemberType").InnerText.CompareTo (
1057 y.SelectSingleNode ("MemberType").InnerText);
1061 // same type -- must be an overloaded method. Sort based on type
1062 // parameter count, then parameter count, then by the parameter
1064 XmlNodeList xTypeParams = x.SelectNodes ("TypeParameters/TypeParameter");
1065 XmlNodeList yTypeParams = y.SelectNodes ("TypeParameters/TypeParameter");
1066 if (xTypeParams.Count != yTypeParams.Count)
1067 return xTypeParams.Count <= yTypeParams.Count ? -1 : 1;
1068 for (int i = 0; i < xTypeParams.Count; ++i) {
1069 r = xTypeParams [i].Attributes ["Name"].Value.CompareTo (
1070 yTypeParams [i].Attributes ["Name"].Value);
1075 XmlNodeList xParams = x.SelectNodes ("Parameters/Parameter");
1076 XmlNodeList yParams = y.SelectNodes ("Parameters/Parameter");
1077 if (xParams.Count != yParams.Count)
1078 return xParams.Count <= yParams.Count ? -1 : 1;
1079 for (int i = 0; i < xParams.Count; ++i) {
1080 r = xParams [i].Attributes ["Type"].Value.CompareTo (
1081 yParams [i].Attributes ["Type"].Value);
1085 // all parameters match, but return value might not match if it was
1086 // changed between one version and another.
1087 XmlNode xReturn = x.SelectSingleNode ("ReturnValue/ReturnType");
1088 XmlNode yReturn = y.SelectSingleNode ("ReturnValue/ReturnType");
1089 if (xReturn != null && yReturn != null) {
1090 r = xReturn.InnerText.CompareTo (yReturn.InnerText);
1099 static readonly MemberComparer DefaultMemberComparer = new MemberComparer ();
1101 private static void SortTypeMembers (XmlNode members)
1103 if (members == null)
1105 SortXmlNodes (members, members.SelectNodes ("Member"), DefaultMemberComparer);
1108 private static bool MemberDocsHaveUserContent (XmlNode e)
1110 e = (XmlElement)e.SelectSingleNode("Docs");
1111 if (e == null) return false;
1112 foreach (XmlElement d in e.SelectNodes("*"))
1113 if (d.InnerText != "" && !d.InnerText.StartsWith("To be added"))
1118 // UPDATE HELPER FUNCTIONS
1120 // CREATE A STUB DOCUMENTATION FILE
1122 public XmlElement StubType (TypeDefinition type, string output)
1124 string typesig = typeFormatters [0].GetDeclaration (type);
1125 if (typesig == null) return null; // not publicly visible
1127 XmlDocument doc = new XmlDocument();
1128 XmlElement root = doc.CreateElement("Type");
1129 doc.AppendChild (root);
1131 DoUpdateType2 ("New Type", doc, type, output, true);
1136 private XmlElement CreateSinceNode (XmlDocument doc)
1138 XmlElement s = doc.CreateElement ("since");
1139 s.SetAttribute ("version", since);
1143 // STUBBING/UPDATING FUNCTIONS
1145 public void UpdateType (XmlElement root, TypeDefinition type)
1147 root.SetAttribute("Name", GetDocTypeName (type));
1148 root.SetAttribute("FullName", GetDocTypeFullName (type));
1150 foreach (MemberFormatter f in typeFormatters) {
1151 string element = "TypeSignature[@Language='" + f.Language + "']";
1152 WriteElementAttribute (root, element, "Language", f.Language);
1153 WriteElementAttribute (root, element, "Value", f.GetDeclaration (type));
1156 XmlElement ass = WriteElement(root, "AssemblyInfo");
1157 WriteElementText(ass, "AssemblyName", type.Module.Assembly.Name.Name);
1158 if (!no_assembly_versions) {
1159 UpdateAssemblyVersions (root, type, true);
1162 var versions = ass.SelectNodes ("AssemblyVersion").Cast<XmlNode> ().ToList ();
1163 foreach (var version in versions)
1164 ass.RemoveChild (version);
1166 if (!string.IsNullOrEmpty (type.Module.Assembly.Name.Culture))
1167 WriteElementText(ass, "AssemblyCulture", type.Module.Assembly.Name.Culture);
1169 ClearElement(ass, "AssemblyCulture");
1171 // Why-oh-why do we put assembly attributes in each type file?
1172 // Neither monodoc nor monodocs2html use them, so I'm deleting them
1173 // since they're outdated in current docs, and a waste of space.
1174 //MakeAttributes(ass, type.Assembly, true);
1175 XmlNode assattrs = ass.SelectSingleNode("Attributes");
1176 if (assattrs != null)
1177 ass.RemoveChild(assattrs);
1179 NormalizeWhitespace(ass);
1181 if (type.IsGenericType ()) {
1182 MakeTypeParameters (root, type.GenericParameters);
1184 ClearElement(root, "TypeParameters");
1187 if (type.BaseType != null) {
1188 XmlElement basenode = WriteElement(root, "Base");
1190 string basetypename = GetDocTypeFullName (type.BaseType);
1191 if (basetypename == "System.MulticastDelegate") basetypename = "System.Delegate";
1192 WriteElementText(root, "Base/BaseTypeName", basetypename);
1194 // Document how this type instantiates the generic parameters of its base type
1195 TypeReference origBase = type.BaseType.GetElementType ();
1196 if (origBase.IsGenericType ()) {
1197 ClearElement(basenode, "BaseTypeArguments");
1198 GenericInstanceType baseInst = type.BaseType as GenericInstanceType;
1199 IList<TypeReference> baseGenArgs = baseInst == null ? null : baseInst.GenericArguments;
1200 IList<GenericParameter> baseGenParams = origBase.GenericParameters;
1201 if (baseGenArgs.Count != baseGenParams.Count)
1202 throw new InvalidOperationException ("internal error: number of generic arguments doesn't match number of generic parameters.");
1203 for (int i = 0; baseGenArgs != null && i < baseGenArgs.Count; i++) {
1204 GenericParameter param = baseGenParams [i];
1205 TypeReference value = baseGenArgs [i];
1207 XmlElement bta = WriteElement(basenode, "BaseTypeArguments");
1208 XmlElement arg = bta.OwnerDocument.CreateElement("BaseTypeArgument");
1209 bta.AppendChild(arg);
1210 arg.SetAttribute ("TypeParamName", param.Name);
1211 arg.InnerText = GetDocTypeFullName (value);
1215 ClearElement(root, "Base");
1218 if (!DocUtils.IsDelegate (type) && !type.IsEnum) {
1219 IEnumerable<TypeReference> userInterfaces = DocUtils.GetUserImplementedInterfaces (type);
1220 List<string> interface_names = userInterfaces
1221 .Select (iface => GetDocTypeFullName (iface))
1225 XmlElement interfaces = WriteElement(root, "Interfaces");
1226 interfaces.RemoveAll();
1227 foreach (string iname in interface_names) {
1228 XmlElement iface = root.OwnerDocument.CreateElement("Interface");
1229 interfaces.AppendChild(iface);
1230 WriteElementText(iface, "InterfaceName", iname);
1233 ClearElement(root, "Interfaces");
1236 MakeAttributes (root, GetCustomAttributes (type));
1238 if (DocUtils.IsDelegate (type)) {
1239 MakeTypeParameters (root, type.GenericParameters);
1240 MakeParameters(root, type.GetMethod("Invoke").Parameters);
1241 MakeReturnValue(root, type.GetMethod("Invoke"));
1244 DocsNodeInfo typeInfo = new DocsNodeInfo (WriteElement(root, "Docs"), type);
1245 MakeDocNode (typeInfo);
1247 if (!DocUtils.IsDelegate (type))
1248 WriteElement (root, "Members");
1250 NormalizeWhitespace(root);
1253 internal static IEnumerable<T> Sort<T> (IEnumerable<T> list)
1255 List<T> l = new List<T> (list);
1260 private void UpdateMember (DocsNodeInfo info)
1262 XmlElement me = (XmlElement) info.Node;
1263 MemberReference mi = info.Member;
1265 foreach (MemberFormatter f in memberFormatters) {
1266 string element = "MemberSignature[@Language='" + f.Language + "']";
1267 WriteElementAttribute (me, element, "Language", f.Language);
1268 WriteElementAttribute (me, element, "Value", f.GetDeclaration (mi));
1271 WriteElementText(me, "MemberType", GetMemberType(mi));
1273 if (!no_assembly_versions) {
1274 UpdateAssemblyVersions (me, mi, true);
1277 ClearElement (me, "AssemblyInfo");
1280 MakeAttributes (me, GetCustomAttributes (mi));
1282 MakeReturnValue(me, mi);
1283 if (mi is MethodReference) {
1284 MethodReference mb = (MethodReference) mi;
1285 if (mb.IsGenericMethod ())
1286 MakeTypeParameters (me, mb.GenericParameters);
1288 MakeParameters(me, mi);
1291 if (mi is FieldDefinition && GetFieldConstValue ((FieldDefinition)mi, out fieldValue))
1292 WriteElementText(me, "MemberValue", fieldValue);
1294 info.Node = WriteElement (me, "Docs");
1296 UpdateExtensionMethods (me, info);
1299 IEnumerable<string> GetCustomAttributes (MemberReference mi)
1301 IEnumerable<string> attrs = Enumerable.Empty<string>();
1303 ICustomAttributeProvider p = mi as ICustomAttributeProvider;
1305 attrs = attrs.Concat (GetCustomAttributes (p.CustomAttributes, ""));
1307 PropertyDefinition pd = mi as PropertyDefinition;
1309 if (pd.GetMethod != null)
1310 attrs = attrs.Concat (GetCustomAttributes (pd.GetMethod.CustomAttributes, "get: "));
1311 if (pd.SetMethod != null)
1312 attrs = attrs.Concat (GetCustomAttributes (pd.SetMethod.CustomAttributes, "set: "));
1315 EventDefinition ed = mi as EventDefinition;
1317 if (ed.AddMethod != null)
1318 attrs = attrs.Concat (GetCustomAttributes (ed.AddMethod.CustomAttributes, "add: "));
1319 if (ed.RemoveMethod != null)
1320 attrs = attrs.Concat (GetCustomAttributes (ed.RemoveMethod.CustomAttributes, "remove: "));
1326 IEnumerable<string> GetCustomAttributes (IList<CustomAttribute> attributes, string prefix)
1328 foreach (CustomAttribute attribute in attributes.OrderBy (ca => ca.AttributeType.FullName)) {
1330 TypeDefinition attrType = attribute.AttributeType as TypeDefinition;
1331 if (attrType != null && !IsPublic (attrType))
1333 if (slashdocFormatter.GetName (attribute.AttributeType) == null)
1336 if (Array.IndexOf (IgnorableAttributes, attribute.AttributeType.FullName) >= 0)
1339 StringList fields = new StringList ();
1341 for (int i = 0; i < attribute.ConstructorArguments.Count; ++i) {
1342 CustomAttributeArgument argument = attribute.ConstructorArguments [i];
1343 fields.Add (MakeAttributesValueString (
1348 (from namedArg in attribute.Fields
1349 select new { Type=namedArg.Argument.Type, Name=namedArg.Name, Value=namedArg.Argument.Value })
1351 (from namedArg in attribute.Properties
1352 select new { Type=namedArg.Argument.Type, Name=namedArg.Name, Value=namedArg.Argument.Value }))
1353 .OrderBy (v => v.Name);
1354 foreach (var d in namedArgs)
1355 fields.Add (string.Format ("{0}={1}", d.Name,
1356 MakeAttributesValueString (d.Value, d.Type)));
1358 string a2 = String.Join(", ", fields.ToArray ());
1359 if (a2 != "") a2 = "(" + a2 + ")";
1361 string name = attribute.Constructor.DeclaringType.FullName;
1362 if (name.EndsWith("Attribute")) name = name.Substring(0, name.Length-"Attribute".Length);
1363 yield return prefix + name + a2;
1367 static readonly string[] ValidExtensionMembers = {
1376 static readonly string[] ValidExtensionDocMembers = {
1382 private void UpdateExtensionMethods (XmlElement e, DocsNodeInfo info)
1384 MethodDefinition me = info.Member as MethodDefinition;
1387 if (info.Parameters.Count < 1)
1389 if (!DocUtils.IsExtensionMethod (me))
1392 XmlNode em = e.OwnerDocument.CreateElement ("ExtensionMethod");
1393 XmlNode member = e.CloneNode (true);
1394 em.AppendChild (member);
1395 RemoveExcept (member, ValidExtensionMembers);
1396 RemoveExcept (member.SelectSingleNode ("Docs"), ValidExtensionDocMembers);
1397 WriteElementText (member, "MemberType", "ExtensionMethod");
1398 XmlElement link = member.OwnerDocument.CreateElement ("Link");
1399 link.SetAttribute ("Type", slashdocFormatter.GetName (me.DeclaringType));
1400 link.SetAttribute ("Member", slashdocFormatter.GetDeclaration (me));
1401 member.AppendChild (link);
1402 AddTargets (em, info);
1404 extensionMethods.Add (em);
1407 private static void RemoveExcept (XmlNode node, string[] except)
1411 MyXmlNodeList remove = null;
1412 foreach (XmlNode n in node.ChildNodes) {
1413 if (Array.BinarySearch (except, n.Name) < 0) {
1415 remove = new MyXmlNodeList ();
1420 foreach (XmlNode n in remove)
1421 node.RemoveChild (n);
1424 private static void AddTargets (XmlNode member, DocsNodeInfo info)
1426 XmlElement targets = member.OwnerDocument.CreateElement ("Targets");
1427 member.PrependChild (targets);
1428 if (!(info.Parameters [0].ParameterType is GenericParameter)) {
1429 AppendElementAttributeText (targets, "Target", "Type",
1430 slashdocFormatter.GetDeclaration (info.Parameters [0].ParameterType));
1433 GenericParameter gp = (GenericParameter) info.Parameters [0].ParameterType;
1434 IList<TypeReference> constraints = gp.Constraints;
1435 if (constraints.Count == 0)
1436 AppendElementAttributeText (targets, "Target", "Type", "System.Object");
1438 foreach (TypeReference c in constraints)
1439 AppendElementAttributeText(targets, "Target", "Type",
1440 slashdocFormatter.GetDeclaration (c));
1444 private static bool GetFieldConstValue (FieldDefinition field, out string value)
1447 TypeDefinition type = field.DeclaringType.Resolve ();
1448 if (type != null && type.IsEnum) return false;
1450 if (type != null && type.IsGenericType ()) return false;
1451 if (!field.HasConstant)
1453 if (field.IsLiteral) {
1454 object val = field.Constant;
1455 if (val == null) value = "null";
1456 else if (val is Enum) value = val.ToString();
1457 else if (val is IFormattable) {
1458 value = ((IFormattable)val).ToString();
1460 value = "\"" + value + "\"";
1462 if (value != null && value != "")
1468 // XML HELPER FUNCTIONS
1470 internal static XmlElement WriteElement(XmlNode parent, string element) {
1471 XmlElement ret = (XmlElement)parent.SelectSingleNode(element);
1473 string[] path = element.Split('/');
1474 foreach (string p in path) {
1475 ret = (XmlElement)parent.SelectSingleNode(p);
1478 if (ename.IndexOf('[') >= 0) // strip off XPath predicate
1479 ename = ename.Substring(0, ename.IndexOf('['));
1480 ret = parent.OwnerDocument.CreateElement(ename);
1481 parent.AppendChild(ret);
1490 private static void WriteElementText(XmlNode parent, string element, string value) {
1491 XmlElement node = WriteElement(parent, element);
1492 node.InnerText = value;
1495 static XmlElement AppendElementText (XmlNode parent, string element, string value)
1497 XmlElement n = parent.OwnerDocument.CreateElement (element);
1498 parent.AppendChild (n);
1499 n.InnerText = value;
1503 static XmlElement AppendElementAttributeText (XmlNode parent, string element, string attribute, string value)
1505 XmlElement n = parent.OwnerDocument.CreateElement (element);
1506 parent.AppendChild (n);
1507 n.SetAttribute (attribute, value);
1511 internal static XmlNode CopyNode (XmlNode source, XmlNode dest)
1513 XmlNode copy = dest.OwnerDocument.ImportNode (source, true);
1514 dest.AppendChild (copy);
1518 private static void WriteElementInitialText(XmlElement parent, string element, string value) {
1519 XmlElement node = (XmlElement)parent.SelectSingleNode(element);
1522 node = WriteElement(parent, element);
1523 node.InnerText = value;
1525 private static void WriteElementAttribute(XmlElement parent, string element, string attribute, string value) {
1526 XmlElement node = WriteElement(parent, element);
1527 if (node.GetAttribute(attribute) == value) return;
1528 node.SetAttribute(attribute, value);
1530 internal static void ClearElement(XmlElement parent, string name) {
1531 XmlElement node = (XmlElement)parent.SelectSingleNode(name);
1533 parent.RemoveChild(node);
1536 // DOCUMENTATION HELPER FUNCTIONS
1538 private void MakeDocNode (DocsNodeInfo info)
1540 List<GenericParameter> genericParams = info.GenericParameters;
1541 IList<ParameterDefinition> parameters = info.Parameters;
1542 TypeReference returntype = info.ReturnType;
1543 bool returnisreturn = info.ReturnIsReturn;
1544 XmlElement e = info.Node;
1545 bool addremarks = info.AddRemarks;
1547 WriteElementInitialText(e, "summary", "To be added.");
1549 if (parameters != null) {
1550 string[] values = new string [parameters.Count];
1551 for (int i = 0; i < values.Length; ++i)
1552 values [i] = parameters [i].Name;
1553 UpdateParameters (e, "param", values);
1556 if (genericParams != null) {
1557 string[] values = new string [genericParams.Count];
1558 for (int i = 0; i < values.Length; ++i)
1559 values [i] = genericParams [i].Name;
1560 UpdateParameters (e, "typeparam", values);
1563 string retnodename = null;
1564 if (returntype != null && returntype.FullName != "System.Void") { // FIXME
1565 retnodename = returnisreturn ? "returns" : "value";
1566 string retnodename_other = !returnisreturn ? "returns" : "value";
1568 // If it has a returns node instead of a value node, change its name.
1569 XmlElement retother = (XmlElement)e.SelectSingleNode(retnodename_other);
1570 if (retother != null) {
1571 XmlElement retnode = e.OwnerDocument.CreateElement(retnodename);
1572 foreach (XmlNode node in retother)
1573 retnode.AppendChild(node.CloneNode(true));
1574 e.ReplaceChild(retnode, retother);
1576 WriteElementInitialText(e, retnodename, "To be added.");
1579 ClearElement(e, "returns");
1580 ClearElement(e, "value");
1584 WriteElementInitialText(e, "remarks", "To be added.");
1586 if (exceptions.HasValue && info.Member != null &&
1587 (exceptions.Value & ExceptionLocations.AddedMembers) == 0) {
1588 UpdateExceptions (e, info.Member);
1591 foreach (DocumentationImporter importer in importers)
1592 importer.ImportDocumentation (info);
1594 OrderDocsNodes (e, e.ChildNodes);
1595 NormalizeWhitespace(e);
1598 static readonly string[] DocsNodeOrder = {
1599 "typeparam", "param", "summary", "returns", "value", "remarks",
1602 private static void OrderDocsNodes (XmlNode docs, XmlNodeList children)
1604 MyXmlNodeList newChildren = new MyXmlNodeList (children.Count);
1605 for (int i = 0; i < DocsNodeOrder.Length; ++i) {
1606 for (int j = 0; j < children.Count; ++j) {
1607 XmlNode c = children [j];
1608 if (c.Name == DocsNodeOrder [i]) {
1609 newChildren.Add (c);
1613 if (newChildren.Count >= 0)
1614 docs.PrependChild ((XmlNode) newChildren [0]);
1615 for (int i = 1; i < newChildren.Count; ++i) {
1616 XmlNode prev = (XmlNode) newChildren [i-1];
1617 XmlNode cur = (XmlNode) newChildren [i];
1618 docs.RemoveChild (cur);
1619 docs.InsertAfter (cur, prev);
1624 private void UpdateParameters (XmlElement e, string element, string[] values)
1626 if (values != null) {
1627 XmlNode[] paramnodes = new XmlNode[values.Length];
1629 // Some documentation had param nodes with leading spaces.
1630 foreach (XmlElement paramnode in e.SelectNodes(element)){
1631 paramnode.SetAttribute("name", paramnode.GetAttribute("name").Trim());
1634 // If a member has only one parameter, we can track changes to
1635 // the name of the parameter easily.
1636 if (values.Length == 1 && e.SelectNodes(element).Count == 1) {
1637 UpdateParameterName (e, (XmlElement) e.SelectSingleNode(element), values [0]);
1640 bool reinsert = false;
1642 // Pick out existing and still-valid param nodes, and
1643 // create nodes for parameters not in the file.
1644 Hashtable seenParams = new Hashtable();
1645 for (int pi = 0; pi < values.Length; pi++) {
1646 string p = values [pi];
1649 paramnodes[pi] = e.SelectSingleNode(element + "[@name='" + p + "']");
1650 if (paramnodes[pi] != null) continue;
1652 XmlElement pe = e.OwnerDocument.CreateElement(element);
1653 pe.SetAttribute("name", p);
1654 pe.InnerText = "To be added.";
1655 paramnodes[pi] = pe;
1659 // Remove parameters that no longer exist and check all params are in the right order.
1661 MyXmlNodeList todelete = new MyXmlNodeList ();
1662 foreach (XmlElement paramnode in e.SelectNodes(element)) {
1663 string name = paramnode.GetAttribute("name");
1664 if (!seenParams.ContainsKey(name)) {
1665 if (!delete && !paramnode.InnerText.StartsWith("To be added")) {
1666 Warning ("The following param node can only be deleted if the --delete option is given: ");
1667 if (e.ParentNode == e.OwnerDocument.DocumentElement) {
1669 Warning ("\tXPath=/Type[@FullName=\"{0}\"]/Docs/param[@name=\"{1}\"]",
1670 e.OwnerDocument.DocumentElement.GetAttribute ("FullName"),
1674 Warning ("\tXPath=/Type[@FullName=\"{0}\"]//Member[@MemberName=\"{1}\"]/Docs/param[@name=\"{2}\"]",
1675 e.OwnerDocument.DocumentElement.GetAttribute ("FullName"),
1676 e.ParentNode.Attributes ["MemberName"].Value,
1679 Warning ("\tValue={0}", paramnode.OuterXml);
1681 todelete.Add (paramnode);
1686 if ((int)seenParams[name] != idx)
1692 foreach (XmlNode n in todelete) {
1693 n.ParentNode.RemoveChild (n);
1696 // Re-insert the parameter nodes at the top of the doc section.
1698 for (int pi = values.Length-1; pi >= 0; pi--)
1699 e.PrependChild(paramnodes[pi]);
1701 // Clear all existing param nodes
1702 foreach (XmlNode paramnode in e.SelectNodes(element)) {
1703 if (!delete && !paramnode.InnerText.StartsWith("To be added")) {
1704 Console.WriteLine("The following param node can only be deleted if the --delete option is given:");
1705 Console.WriteLine(paramnode.OuterXml);
1707 paramnode.ParentNode.RemoveChild(paramnode);
1713 private static void UpdateParameterName (XmlElement docs, XmlElement pe, string newName)
1715 string existingName = pe.GetAttribute ("name");
1716 pe.SetAttribute ("name", newName);
1717 if (existingName == newName)
1719 foreach (XmlElement paramref in docs.SelectNodes (".//paramref"))
1720 if (paramref.GetAttribute ("name").Trim () == existingName)
1721 paramref.SetAttribute ("name", newName);
1724 class CrefComparer : XmlNodeComparer {
1726 public CrefComparer ()
1730 public override int Compare (XmlNode x, XmlNode y)
1732 string xType = x.Attributes ["cref"].Value;
1733 string yType = y.Attributes ["cref"].Value;
1734 string xNamespace = GetNamespace (xType);
1735 string yNamespace = GetNamespace (yType);
1737 int c = xNamespace.CompareTo (yNamespace);
1740 return xType.CompareTo (yType);
1743 static string GetNamespace (string type)
1745 int n = type.LastIndexOf ('.');
1747 return type.Substring (0, n);
1748 return string.Empty;
1752 private void UpdateExceptions (XmlNode docs, MemberReference member)
1754 foreach (var source in new ExceptionLookup (exceptions.Value)[member]) {
1755 string cref = slashdocFormatter.GetDeclaration (source.Exception);
1756 var node = docs.SelectSingleNode ("exception[@cref='" + cref + "']");
1759 XmlElement e = docs.OwnerDocument.CreateElement ("exception");
1760 e.SetAttribute ("cref", cref);
1761 e.InnerXml = "To be added; from: <see cref=\"" +
1762 string.Join ("\" />, <see cref=\"",
1763 source.Sources.Select (m => slashdocFormatter.GetDeclaration (m))
1766 docs.AppendChild (e);
1768 SortXmlNodes (docs, docs.SelectNodes ("exception"),
1769 new CrefComparer ());
1772 private static void NormalizeWhitespace(XmlElement e) {
1773 // Remove all text and whitespace nodes from the element so it
1774 // is outputted with nice indentation and no blank lines.
1775 ArrayList deleteNodes = new ArrayList();
1776 foreach (XmlNode n in e)
1777 if (n is XmlText || n is XmlWhitespace || n is XmlSignificantWhitespace)
1779 foreach (XmlNode n in deleteNodes)
1780 n.ParentNode.RemoveChild(n);
1783 private static bool UpdateAssemblyVersions (XmlElement root, MemberReference member, bool add)
1785 TypeDefinition type = member as TypeDefinition;
1787 type = member.DeclaringType as TypeDefinition;
1788 return UpdateAssemblyVersions(root, new string[]{ GetAssemblyVersion (type.Module.Assembly) }, add);
1791 private static string GetAssemblyVersion (AssemblyDefinition assembly)
1793 return assembly.Name.Version.ToString();
1796 private static bool UpdateAssemblyVersions(XmlElement root, string[] assemblyVersions, bool add)
1798 XmlElement e = (XmlElement) root.SelectSingleNode ("AssemblyInfo");
1800 e = root.OwnerDocument.CreateElement("AssemblyInfo");
1801 root.AppendChild(e);
1803 List<XmlNode> matches = e.SelectNodes ("AssemblyVersion").Cast<XmlNode>()
1804 .Where(v => Array.IndexOf (assemblyVersions, v.InnerText) >= 0)
1806 // matches.Count > 0 && add: ignore -- already present
1807 if (matches.Count > 0 && !add) {
1808 foreach (XmlNode c in matches)
1811 else if (matches.Count == 0 && add) {
1812 foreach (string sv in assemblyVersions) {
1813 XmlElement c = root.OwnerDocument.CreateElement("AssemblyVersion");
1818 // matches.Count == 0 && !add: ignore -- already not present
1820 XmlNodeList avs = e.SelectNodes ("AssemblyVersion");
1821 SortXmlNodes (e, avs, new VersionComparer ());
1823 return avs.Count != 0;
1826 // FIXME: get TypeReferences instead of string comparison?
1827 private static string[] IgnorableAttributes = {
1828 // Security related attributes
1829 "System.Reflection.AssemblyKeyFileAttribute",
1830 "System.Reflection.AssemblyDelaySignAttribute",
1831 // Present in @RefType
1832 "System.Runtime.InteropServices.OutAttribute",
1833 // For naming the indexer to use when not using indexers
1834 "System.Reflection.DefaultMemberAttribute",
1835 // for decimal constants
1836 "System.Runtime.CompilerServices.DecimalConstantAttribute",
1837 // compiler generated code
1838 "System.Runtime.CompilerServices.CompilerGeneratedAttribute",
1839 // more compiler generated code, e.g. iterator methods
1840 "System.Diagnostics.DebuggerHiddenAttribute",
1841 "System.Runtime.CompilerServices.FixedBufferAttribute",
1842 "System.Runtime.CompilerServices.UnsafeValueTypeAttribute",
1843 // extension methods
1844 "System.Runtime.CompilerServices.ExtensionAttribute",
1847 private void MakeAttributes (XmlElement root, IEnumerable<string> attributes)
1849 if (!attributes.Any ()) {
1850 ClearElement (root, "Attributes");
1854 XmlElement e = (XmlElement)root.SelectSingleNode("Attributes");
1858 e = root.OwnerDocument.CreateElement("Attributes");
1860 foreach (string attribute in attributes) {
1861 XmlElement ae = root.OwnerDocument.CreateElement("Attribute");
1864 WriteElementText(ae, "AttributeName", attribute);
1867 if (e.ParentNode == null)
1868 root.AppendChild(e);
1870 NormalizeWhitespace(e);
1873 private static string MakeAttributesValueString (object v, TypeReference valueType)
1877 if (valueType.FullName == "System.Type")
1878 return "typeof(" + v.ToString () + ")";
1879 if (valueType.FullName == "System.String")
1880 return "\"" + v.ToString () + "\"";
1882 return (bool)v ? "true" : "false";
1883 TypeDefinition valueDef = valueType.Resolve ();
1884 if (valueDef == null || !valueDef.IsEnum)
1885 return v.ToString ();
1886 string typename = GetDocTypeFullName (valueType);
1887 var values = GetEnumerationValues (valueDef);
1888 long c = ToInt64 (v);
1889 if (values.ContainsKey (c))
1890 return typename + "." + values [c];
1891 if (valueDef.CustomAttributes.Any (ca => ca.AttributeType.FullName == "System.FlagsAttribute")) {
1892 return string.Join (" | ",
1893 (from i in values.Keys
1895 select typename + "." + values [i])
1898 return "(" + GetDocTypeFullName (valueType) + ") " + v.ToString ();
1901 private static Dictionary<long, string> GetEnumerationValues (TypeDefinition type)
1903 var values = new Dictionary<long, string> ();
1905 (from f in type.Fields
1906 where !(f.IsRuntimeSpecialName || f.IsSpecialName)
1908 values [ToInt64 (f.Constant)] = f.Name;
1913 static long ToInt64 (object value)
1916 return (long) (ulong) value;
1917 return Convert.ToInt64 (value);
1920 private void MakeParameters (XmlElement root, IList<ParameterDefinition> parameters)
1922 XmlElement e = WriteElement(root, "Parameters");
1924 foreach (ParameterDefinition p in parameters) {
1925 XmlElement pe = root.OwnerDocument.CreateElement("Parameter");
1927 pe.SetAttribute("Name", p.Name);
1928 pe.SetAttribute("Type", GetDocParameterType (p.ParameterType));
1929 if (p.ParameterType is ByReferenceType) {
1930 if (p.IsOut) pe.SetAttribute("RefType", "out");
1931 else pe.SetAttribute("RefType", "ref");
1933 MakeAttributes (pe, GetCustomAttributes (p.CustomAttributes, ""));
1937 private void MakeTypeParameters (XmlElement root, IList<GenericParameter> typeParams)
1939 if (typeParams == null || typeParams.Count == 0) {
1940 XmlElement f = (XmlElement) root.SelectSingleNode ("TypeParameters");
1942 root.RemoveChild (f);
1945 XmlElement e = WriteElement(root, "TypeParameters");
1947 foreach (GenericParameter t in typeParams) {
1948 XmlElement pe = root.OwnerDocument.CreateElement("TypeParameter");
1950 pe.SetAttribute("Name", t.Name);
1951 MakeAttributes (pe, GetCustomAttributes (t.CustomAttributes, ""));
1952 XmlElement ce = (XmlElement) e.SelectSingleNode ("Constraints");
1953 IList<TypeReference> constraints = t.Constraints;
1954 GenericParameterAttributes attrs = t.Attributes;
1955 if (attrs == GenericParameterAttributes.NonVariant && constraints.Count == 0) {
1963 ce = root.OwnerDocument.CreateElement ("Constraints");
1965 pe.AppendChild (ce);
1966 if ((attrs & GenericParameterAttributes.Contravariant) != 0)
1967 AppendElementText (ce, "ParameterAttribute", "Contravariant");
1968 if ((attrs & GenericParameterAttributes.Covariant) != 0)
1969 AppendElementText (ce, "ParameterAttribute", "Covariant");
1970 if ((attrs & GenericParameterAttributes.DefaultConstructorConstraint) != 0)
1971 AppendElementText (ce, "ParameterAttribute", "DefaultConstructorConstraint");
1972 if ((attrs & GenericParameterAttributes.NotNullableValueTypeConstraint) != 0)
1973 AppendElementText (ce, "ParameterAttribute", "NotNullableValueTypeConstraint");
1974 if ((attrs & GenericParameterAttributes.ReferenceTypeConstraint) != 0)
1975 AppendElementText (ce, "ParameterAttribute", "ReferenceTypeConstraint");
1976 foreach (TypeReference c in constraints) {
1977 TypeDefinition cd = c.Resolve ();
1978 AppendElementText (ce,
1979 (cd != null && cd.IsInterface) ? "InterfaceName" : "BaseTypeName",
1980 GetDocTypeFullName (c));
1985 private void MakeParameters (XmlElement root, MemberReference mi)
1987 if (mi is MethodDefinition && ((MethodDefinition) mi).IsConstructor)
1988 MakeParameters (root, ((MethodDefinition)mi).Parameters);
1989 else if (mi is MethodDefinition) {
1990 MethodDefinition mb = (MethodDefinition) mi;
1991 IList<ParameterDefinition> parameters = mb.Parameters;
1992 MakeParameters(root, parameters);
1993 if (parameters.Count > 0 && DocUtils.IsExtensionMethod (mb)) {
1994 XmlElement p = (XmlElement) root.SelectSingleNode ("Parameters/Parameter[position()=1]");
1995 p.SetAttribute ("RefType", "this");
1998 else if (mi is PropertyDefinition) {
1999 IList<ParameterDefinition> parameters = ((PropertyDefinition)mi).Parameters;
2000 if (parameters.Count > 0)
2001 MakeParameters(root, parameters);
2005 else if (mi is FieldDefinition) return;
2006 else if (mi is EventDefinition) return;
2007 else throw new ArgumentException();
2010 internal static string GetDocParameterType (TypeReference type)
2012 return GetDocTypeFullName (type).Replace ("@", "&");
2015 private void MakeReturnValue (XmlElement root, TypeReference type, IList<CustomAttribute> attributes)
2017 XmlElement e = WriteElement(root, "ReturnValue");
2019 WriteElementText(e, "ReturnType", GetDocTypeFullName (type));
2020 if (attributes != null)
2021 MakeAttributes(e, GetCustomAttributes (attributes, ""));
2024 private void MakeReturnValue (XmlElement root, MemberReference mi)
2026 if (mi is MethodDefinition && ((MethodDefinition) mi).IsConstructor)
2028 else if (mi is MethodDefinition)
2029 MakeReturnValue (root, ((MethodDefinition)mi).ReturnType, ((MethodDefinition)mi).MethodReturnType.CustomAttributes);
2030 else if (mi is PropertyDefinition)
2031 MakeReturnValue (root, ((PropertyDefinition)mi).PropertyType, null);
2032 else if (mi is FieldDefinition)
2033 MakeReturnValue (root, ((FieldDefinition)mi).FieldType, null);
2034 else if (mi is EventDefinition)
2035 MakeReturnValue (root, ((EventDefinition)mi).EventType, null);
2037 throw new ArgumentException(mi + " is a " + mi.GetType().FullName);
2040 private XmlElement MakeMember(XmlDocument doc, DocsNodeInfo info)
2042 MemberReference mi = info.Member;
2043 if (mi is TypeDefinition) return null;
2045 string sigs = memberFormatters [0].GetDeclaration (mi);
2046 if (sigs == null) return null; // not publicly visible
2048 // no documentation for property/event accessors. Is there a better way of doing this?
2049 if (mi.Name.StartsWith("get_")) return null;
2050 if (mi.Name.StartsWith("set_")) return null;
2051 if (mi.Name.StartsWith("add_")) return null;
2052 if (mi.Name.StartsWith("remove_")) return null;
2053 if (mi.Name.StartsWith("raise_")) return null;
2055 XmlElement me = doc.CreateElement("Member");
2056 me.SetAttribute("MemberName", GetMemberName (mi));
2060 if (exceptions.HasValue &&
2061 (exceptions.Value & ExceptionLocations.AddedMembers) != 0)
2062 UpdateExceptions (info.Node, info.Member);
2064 if (since != null) {
2065 XmlNode docs = me.SelectSingleNode("Docs");
2066 docs.AppendChild (CreateSinceNode (doc));
2072 internal static string GetMemberName (MemberReference mi)
2074 MethodDefinition mb = mi as MethodDefinition;
2076 PropertyDefinition pi = mi as PropertyDefinition;
2079 return DocUtils.GetPropertyName (pi);
2081 StringBuilder sb = new StringBuilder (mi.Name.Length);
2082 if (!DocUtils.IsExplicitlyImplemented (mb))
2083 sb.Append (mi.Name);
2085 TypeReference iface;
2086 MethodReference ifaceMethod;
2087 DocUtils.GetInfoForExplicitlyImplementedMethod (mb, out iface, out ifaceMethod);
2088 sb.Append (GetDocTypeFullName (iface));
2090 sb.Append (ifaceMethod.Name);
2092 if (mb.IsGenericMethod ()) {
2093 IList<GenericParameter> typeParams = mb.GenericParameters;
2094 if (typeParams.Count > 0) {
2096 sb.Append (typeParams [0].Name);
2097 for (int i = 1; i < typeParams.Count; ++i)
2098 sb.Append (",").Append (typeParams [i].Name);
2102 return sb.ToString ();
2105 /// SIGNATURE GENERATION FUNCTIONS
2106 internal static bool IsPrivate (MemberReference mi)
2108 return memberFormatters [0].GetDeclaration (mi) == null;
2111 internal static string GetMemberType (MemberReference mi)
2113 if (mi is MethodDefinition && ((MethodDefinition) mi).IsConstructor)
2114 return "Constructor";
2115 if (mi is MethodDefinition)
2117 if (mi is PropertyDefinition)
2119 if (mi is FieldDefinition)
2121 if (mi is EventDefinition)
2123 throw new ArgumentException();
2126 private static string GetDocTypeName (TypeReference type)
2128 return docTypeFormatter.GetName (type);
2131 internal static string GetDocTypeFullName (TypeReference type)
2133 return DocTypeFullMemberFormatter.Default.GetName (type);
2136 internal static string GetXPathForMember (DocumentationMember member)
2138 StringBuilder xpath = new StringBuilder ();
2139 xpath.Append ("//Members/Member[@MemberName=\"")
2140 .Append (member.MemberName)
2142 if (member.Parameters != null && member.Parameters.Count > 0) {
2143 xpath.Append ("/Parameters[count(Parameter) = ")
2144 .Append (member.Parameters.Count);
2145 for (int i = 0; i < member.Parameters.Count; ++i) {
2146 xpath.Append (" and Parameter [").Append (i+1).Append ("]/@Type=\"");
2147 xpath.Append (member.Parameters [i]);
2148 xpath.Append ("\"");
2150 xpath.Append ("]/..");
2152 return xpath.ToString ();
2155 public static string GetXPathForMember (XPathNavigator member)
2157 StringBuilder xpath = new StringBuilder ();
2158 xpath.Append ("//Type[@FullName=\"")
2159 .Append (member.SelectSingleNode ("../../@FullName").Value)
2161 xpath.Append ("Members/Member[@MemberName=\"")
2162 .Append (member.SelectSingleNode ("@MemberName").Value)
2164 XPathNodeIterator parameters = member.Select ("Parameters/Parameter");
2165 if (parameters.Count > 0) {
2166 xpath.Append ("/Parameters[count(Parameter) = ")
2167 .Append (parameters.Count);
2169 while (parameters.MoveNext ()) {
2171 xpath.Append (" and Parameter [").Append (i).Append ("]/@Type=\"");
2172 xpath.Append (parameters.Current.Value);
2173 xpath.Append ("\"");
2175 xpath.Append ("]/..");
2177 return xpath.ToString ();
2180 public static string GetXPathForMember (MemberReference member)
2182 StringBuilder xpath = new StringBuilder ();
2183 xpath.Append ("//Type[@FullName=\"")
2184 .Append (member.DeclaringType.FullName)
2186 xpath.Append ("Members/Member[@MemberName=\"")
2187 .Append (GetMemberName (member))
2190 IList<ParameterDefinition> parameters = null;
2191 if (member is MethodDefinition)
2192 parameters = ((MethodDefinition) member).Parameters;
2193 else if (member is PropertyDefinition) {
2194 parameters = ((PropertyDefinition) member).Parameters;
2196 if (parameters != null && parameters.Count > 0) {
2197 xpath.Append ("/Parameters[count(Parameter) = ")
2198 .Append (parameters.Count);
2199 for (int i = 0; i < parameters.Count; ++i) {
2200 xpath.Append (" and Parameter [").Append (i+1).Append ("]/@Type=\"");
2201 xpath.Append (GetDocParameterType (parameters [i].ParameterType));
2202 xpath.Append ("\"");
2204 xpath.Append ("]/..");
2206 return xpath.ToString ();
2210 static class CecilExtensions {
2211 public static IEnumerable<MemberReference> GetMembers (this TypeDefinition type)
2213 foreach (var c in type.Methods.Where (m => m.IsConstructor))
2214 yield return (MemberReference) c;
2215 foreach (var e in type.Events)
2216 yield return (MemberReference) e;
2217 foreach (var f in type.Fields)
2218 yield return (MemberReference) f;
2219 foreach (var m in type.Methods.Where (m => !m.IsConstructor))
2220 yield return (MemberReference) m;
2221 foreach (var t in type.NestedTypes)
2222 yield return (MemberReference) t;
2223 foreach (var p in type.Properties)
2224 yield return (MemberReference) p;
2227 public static IEnumerable<MemberReference> GetMembers (this TypeDefinition type, string member)
2229 return GetMembers (type).Where (m => m.Name == member);
2232 public static MemberReference GetMember (this TypeDefinition type, string member)
2234 return GetMembers (type, member).EnsureZeroOrOne ();
2237 static T EnsureZeroOrOne<T> (this IEnumerable<T> source)
2239 if (source.Count () > 1)
2240 throw new InvalidOperationException ("too many matches");
2241 return source.FirstOrDefault ();
2244 public static MethodDefinition GetMethod (this TypeDefinition type, string method)
2247 .Where (m => m.Name == method)
2248 .EnsureZeroOrOne ();
2251 public static IEnumerable<MemberReference> GetDefaultMembers (this TypeReference type)
2253 TypeDefinition def = type as TypeDefinition;
2255 return new MemberReference [0];
2256 CustomAttribute defMemberAttr = def.CustomAttributes
2257 .FirstOrDefault (c => c.AttributeType.FullName == "System.Reflection.DefaultMemberAttribute");
2258 if (defMemberAttr == null)
2259 return new MemberReference [0];
2260 string name = (string) defMemberAttr.ConstructorArguments [0].Value;
2261 return def.Properties
2262 .Where (p => p.Name == name)
2263 .Select (p => (MemberReference) p);
2266 public static IEnumerable<TypeDefinition> GetTypes (this AssemblyDefinition assembly)
2268 return assembly.Modules.SelectMany (md => md.GetAllTypes ());
2271 public static TypeDefinition GetType (this AssemblyDefinition assembly, string type)
2273 return GetTypes (assembly)
2274 .Where (td => td.FullName == type)
2275 .EnsureZeroOrOne ();
2278 public static bool IsGenericType (this TypeReference type)
2280 return type.GenericParameters.Count > 0;
2283 public static bool IsGenericMethod (this MethodReference method)
2285 return method.GenericParameters.Count > 0;
2288 public static MemberReference Resolve (this MemberReference member)
2290 FieldReference fr = member as FieldReference;
2292 return fr.Resolve ();
2293 MethodReference mr = member as MethodReference;
2295 return mr.Resolve ();
2296 TypeReference tr = member as TypeReference;
2298 return tr.Resolve ();
2299 PropertyReference pr = member as PropertyReference;
2302 EventReference er = member as EventReference;
2305 throw new NotSupportedException ("Cannot find definition for " + member.ToString ());
2308 public static TypeReference GetUnderlyingType (this TypeDefinition type)
2312 return type.Fields.First (f => f.Name == "value__").FieldType;
2315 public static IEnumerable<TypeDefinition> GetAllTypes (this ModuleDefinition self)
2317 return self.Types.SelectMany (t => t.GetAllTypes ());
2320 static IEnumerable<TypeDefinition> GetAllTypes (this TypeDefinition self)
2324 if (!self.HasNestedTypes)
2327 foreach (var type in self.NestedTypes.SelectMany (t => t.GetAllTypes ()))
2332 static class DocUtils {
2333 public static bool IsExplicitlyImplemented (MethodDefinition method)
2335 return method.IsPrivate && method.IsFinal && method.IsVirtual;
2338 public static string GetTypeDotMember (string name)
2340 int startType, startMethod;
2341 startType = startMethod = -1;
2342 for (int i = 0; i < name.Length; ++i) {
2343 if (name [i] == '.') {
2344 startType = startMethod;
2348 return name.Substring (startType+1);
2351 public static string GetMember (string name)
2353 int i = name.LastIndexOf ('.');
2356 return name.Substring (i+1);
2359 public static void GetInfoForExplicitlyImplementedMethod (
2360 MethodDefinition method, out TypeReference iface, out MethodReference ifaceMethod)
2364 if (method.Overrides.Count != 1)
2365 throw new InvalidOperationException ("Could not determine interface type for explicitly-implemented interface member " + method.Name);
2366 iface = method.Overrides [0].DeclaringType;
2367 ifaceMethod = method.Overrides [0];
2370 public static string GetPropertyName (PropertyDefinition pi)
2372 // Issue: (g)mcs-generated assemblies that explicitly implement
2373 // properties don't specify the full namespace, just the
2374 // TypeName.Property; .NET uses Full.Namespace.TypeName.Property.
2375 MethodDefinition method = pi.GetMethod;
2377 method = pi.SetMethod;
2378 if (!IsExplicitlyImplemented (method))
2381 // Need to determine appropriate namespace for this member.
2382 TypeReference iface;
2383 MethodReference ifaceMethod;
2384 GetInfoForExplicitlyImplementedMethod (method, out iface, out ifaceMethod);
2385 return string.Join (".", new string[]{
2386 DocTypeFullMemberFormatter.Default.GetName (iface),
2387 GetMember (pi.Name)});
2390 public static string GetNamespace (TypeReference type)
2392 if (type.GetElementType ().IsNested)
2393 type = type.GetElementType ();
2394 while (type != null && type.IsNested)
2395 type = type.DeclaringType;
2397 return string.Empty;
2398 return type.Namespace;
2401 public static string PathCombine (string dir, string path)
2407 return Path.Combine (dir, path);
2410 public static bool IsExtensionMethod (MethodDefinition method)
2413 method.CustomAttributes
2414 .Any (m => m.AttributeType.FullName == "System.Runtime.CompilerServices.ExtensionAttribute")
2415 && method.DeclaringType.CustomAttributes
2416 .Any (m => m.AttributeType.FullName == "System.Runtime.CompilerServices.ExtensionAttribute");
2419 public static bool IsDelegate (TypeDefinition type)
2421 TypeReference baseRef = type.BaseType;
2422 if (baseRef == null)
2424 return !type.IsAbstract && baseRef.FullName == "System.Delegate" || // FIXME
2425 baseRef.FullName == "System.MulticastDelegate";
2428 public static List<TypeReference> GetDeclaringTypes (TypeReference type)
2430 List<TypeReference> decls = new List<TypeReference> ();
2432 while (type.DeclaringType != null) {
2433 decls.Add (type.DeclaringType);
2434 type = type.DeclaringType;
2440 public static int GetGenericArgumentCount (TypeReference type)
2442 GenericInstanceType inst = type as GenericInstanceType;
2444 ? inst.GenericArguments.Count
2445 : type.GenericParameters.Count;
2448 public static IEnumerable<TypeReference> GetUserImplementedInterfaces (TypeDefinition type)
2450 HashSet<string> inheritedInterfaces = GetInheritedInterfaces (type);
2451 List<TypeReference> userInterfaces = new List<TypeReference> ();
2452 foreach (TypeReference iface in type.Interfaces) {
2453 TypeReference lookup = iface.Resolve () ?? iface;
2454 if (!inheritedInterfaces.Contains (GetQualifiedTypeName (lookup)))
2455 userInterfaces.Add (iface);
2457 return userInterfaces;
2460 private static string GetQualifiedTypeName (TypeReference type)
2462 return "[" + type.Scope.Name + "]" + type.FullName;
2465 private static HashSet<string> GetInheritedInterfaces (TypeDefinition type)
2467 HashSet<string> inheritedInterfaces = new HashSet<string> ();
2468 Action<TypeDefinition> a = null;
2470 if (t == null) return;
2471 foreach (TypeReference r in t.Interfaces) {
2472 inheritedInterfaces.Add (GetQualifiedTypeName (r));
2476 TypeReference baseRef = type.BaseType;
2477 while (baseRef != null) {
2478 TypeDefinition baseDef = baseRef.Resolve ();
2479 if (baseDef != null) {
2481 baseRef = baseDef.BaseType;
2486 foreach (TypeReference r in type.Interfaces)
2488 return inheritedInterfaces;
2492 class DocsNodeInfo {
2493 public DocsNodeInfo (XmlElement node)
2498 public DocsNodeInfo (XmlElement node, TypeDefinition type)
2504 public DocsNodeInfo (XmlElement node, MemberReference member)
2507 SetMemberInfo (member);
2510 void SetType (TypeDefinition type)
2513 throw new ArgumentNullException ("type");
2515 GenericParameters = new List<GenericParameter> (type.GenericParameters);
2516 List<TypeReference> declTypes = DocUtils.GetDeclaringTypes (type);
2517 int maxGenArgs = DocUtils.GetGenericArgumentCount (type);
2518 for (int i = 0; i < declTypes.Count - 1; ++i) {
2519 int remove = System.Math.Min (maxGenArgs,
2520 DocUtils.GetGenericArgumentCount (declTypes [i]));
2521 maxGenArgs -= remove;
2522 while (remove-- > 0)
2523 GenericParameters.RemoveAt (0);
2525 if (DocUtils.IsDelegate (type)) {
2526 Parameters = type.GetMethod("Invoke").Parameters;
2527 ReturnType = type.GetMethod("Invoke").ReturnType;
2528 ReturnIsReturn = true;
2532 void SetMemberInfo (MemberReference member)
2535 throw new ArgumentNullException ("member");
2536 ReturnIsReturn = true;
2540 if (member is MethodReference ) {
2541 MethodReference mr = (MethodReference) member;
2542 Parameters = mr.Parameters;
2543 if (mr.IsGenericMethod ()) {
2544 GenericParameters = new List<GenericParameter> (mr.GenericParameters);
2547 else if (member is PropertyDefinition) {
2548 Parameters = ((PropertyDefinition) member).Parameters;
2551 if (member is MethodDefinition) {
2552 ReturnType = ((MethodDefinition) member).ReturnType;
2553 } else if (member is PropertyDefinition) {
2554 ReturnType = ((PropertyDefinition) member).PropertyType;
2555 ReturnIsReturn = false;
2558 // no remarks section for enum members
2559 if (member.DeclaringType != null && ((TypeDefinition) member.DeclaringType).IsEnum)
2563 public TypeReference ReturnType;
2564 public List<GenericParameter> GenericParameters;
2565 public IList<ParameterDefinition> Parameters;
2566 public bool ReturnIsReturn;
2567 public XmlElement Node;
2568 public bool AddRemarks = true;
2569 public MemberReference Member;
2570 public TypeDefinition Type;
2573 class DocumentationEnumerator {
2575 public virtual IEnumerable<TypeDefinition> GetDocumentationTypes (AssemblyDefinition assembly, List<string> forTypes)
2577 return GetDocumentationTypes (assembly, forTypes, null);
2580 protected IEnumerable<TypeDefinition> GetDocumentationTypes (AssemblyDefinition assembly, List<string> forTypes, HashSet<string> seen)
2582 foreach (TypeDefinition type in assembly.GetTypes()) {
2583 if (forTypes != null && forTypes.BinarySearch (type.FullName) < 0)
2585 if (seen != null && seen.Contains (type.FullName))
2588 foreach (TypeDefinition nested in type.NestedTypes)
2589 yield return nested;
2593 public virtual IEnumerable<DocsNodeInfo> GetDocumentationMembers (XmlDocument basefile, TypeDefinition type)
2595 foreach (XmlElement oldmember in basefile.SelectNodes("Type/Members/Member")) {
2596 if (oldmember.GetAttribute ("__monodocer-seen__") == "true") {
2597 oldmember.RemoveAttribute ("__monodocer-seen__");
2600 MemberReference m = GetMember (type, new DocumentationMember (oldmember));
2602 yield return new DocsNodeInfo (oldmember);
2605 yield return new DocsNodeInfo (oldmember, m);
2610 protected static MemberReference GetMember (TypeDefinition type, DocumentationMember member)
2612 string membertype = member.MemberType;
2614 string returntype = member.ReturnType;
2616 string docName = member.MemberName;
2617 string[] docTypeParams = GetTypeParameters (docName);
2619 // Loop through all members in this type with the same name
2620 foreach (MemberReference mi in GetReflectionMembers (type, docName)) {
2621 if (mi is TypeDefinition) continue;
2622 if (MDocUpdater.GetMemberType(mi) != membertype) continue;
2624 if (MDocUpdater.IsPrivate (mi))
2627 IList<ParameterDefinition> pis = null;
2628 string[] typeParams = null;
2629 if (mi is MethodDefinition) {
2630 MethodDefinition mb = (MethodDefinition) mi;
2631 pis = mb.Parameters;
2632 if (docTypeParams != null && mb.IsGenericMethod ()) {
2633 IList<GenericParameter> args = mb.GenericParameters;
2634 if (args.Count == docTypeParams.Length) {
2635 typeParams = args.Select (p => p.Name).ToArray ();
2639 else if (mi is PropertyDefinition)
2640 pis = ((PropertyDefinition)mi).Parameters;
2642 int mcount = member.Parameters == null ? 0 : member.Parameters.Count;
2643 int pcount = pis == null ? 0 : pis.Count;
2644 if (mcount != pcount)
2647 MethodDefinition mDef = mi as MethodDefinition;
2648 if (mDef != null && !mDef.IsConstructor) {
2649 // Casting operators can overload based on return type.
2650 if (returntype != GetReplacedString (
2651 MDocUpdater.GetDocTypeFullName (((MethodDefinition)mi).ReturnType),
2652 typeParams, docTypeParams)) {
2660 for (int i = 0; i < pis.Count; i++) {
2661 string paramType = GetReplacedString (
2662 MDocUpdater.GetDocParameterType (pis [i].ParameterType),
2663 typeParams, docTypeParams);
2664 if (paramType != (string) member.Parameters [i]) {
2669 if (!good) continue;
2677 static string[] GetTypeParameters (string docName)
2679 if (docName [docName.Length-1] != '>')
2681 StringList types = new StringList ();
2682 int endToken = docName.Length-2;
2683 int i = docName.Length-2;
2685 if (docName [i] == ',' || docName [i] == '<') {
2686 types.Add (docName.Substring (i + 1, endToken - i));
2689 if (docName [i] == '<')
2694 return types.ToArray ();
2697 protected static IEnumerable<MemberReference> GetReflectionMembers (TypeDefinition type, string docName)
2699 // need to worry about 4 forms of //@MemberName values:
2700 // 1. "Normal" (non-generic) member names: GetEnumerator
2702 // 2. Explicitly-implemented interface member names: System.Collections.IEnumerable.Current
2703 // - try as-is, and try type.member (due to "kludge" for property
2705 // 3. "Normal" Generic member names: Sort<T> (CSC)
2706 // - need to remove generic parameters --> "Sort"
2707 // 4. Explicitly-implemented interface members for generic interfaces:
2708 // -- System.Collections.Generic.IEnumerable<T>.Current
2709 // - Try as-is, and try type.member, *keeping* the generic parameters.
2710 // --> System.Collections.Generic.IEnumerable<T>.Current, IEnumerable<T>.Current
2711 // 5. As of 2008-01-02, gmcs will do e.g. 'IFoo`1[A].Method' instead of
2712 // 'IFoo<A>.Method' for explicitly implemented methods; don't interpret
2713 // this as (1) or (2).
2714 if (docName.IndexOf ('<') == -1 && docName.IndexOf ('[') == -1) {
2716 foreach (MemberReference mi in type.GetMembers (docName))
2718 if (CountChars (docName, '.') > 0)
2719 // might be a property; try only type.member instead of
2720 // namespace.type.member.
2721 foreach (MemberReference mi in
2722 type.GetMembers (DocUtils.GetTypeDotMember (docName)))
2729 int startLt, startType, startMethod;
2730 startLt = startType = startMethod = -1;
2731 for (int i = 0; i < docName.Length; ++i) {
2732 switch (docName [i]) {
2741 if (numLt == 0 && (i + 1) < docName.Length)
2742 // there's another character in docName, so this <...> sequence is
2743 // probably part of a generic type -- case 4.
2747 startType = startMethod;
2753 string refName = startLt == -1 ? docName : docName.Substring (0, startLt);
2755 foreach (MemberReference mi in type.GetMembers (refName))
2759 foreach (MemberReference mi in type.GetMembers (refName.Substring (startType + 1)))
2762 // If we _still_ haven't found it, we've hit another generic naming issue:
2763 // post Mono 1.1.18, gmcs generates [[FQTN]] instead of <TypeName> for
2764 // explicitly-implemented METHOD names (not properties), e.g.
2765 // "System.Collections.Generic.IEnumerable`1[[Foo, test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null]].GetEnumerator"
2766 // instead of "System.Collections.Generic.IEnumerable<Foo>.GetEnumerator",
2767 // which the XML docs will contain.
2769 // Alas, we can't derive the Mono name from docName, so we need to iterate
2770 // over all member names, convert them into CSC format, and compare... :-(
2773 foreach (MemberReference mi in type.GetMembers ()) {
2774 if (MDocUpdater.GetMemberName (mi) == docName)
2779 static string GetReplacedString (string typeName, string[] from, string[] to)
2783 for (int i = 0; i < from.Length; ++i)
2784 typeName = typeName.Replace (from [i], to [i]);
2788 private static int CountChars (string s, char c)
2791 for (int i = 0; i < s.Length; ++i) {
2799 class EcmaDocumentationEnumerator : DocumentationEnumerator {
2804 public EcmaDocumentationEnumerator (MDocUpdater app, XmlReader ecmaDocs)
2807 this.ecmadocs = ecmaDocs;
2810 public override IEnumerable<TypeDefinition> GetDocumentationTypes (AssemblyDefinition assembly, List<string> forTypes)
2812 HashSet<string> seen = new HashSet<string> ();
2813 return GetDocumentationTypes (assembly, forTypes, seen)
2814 .Concat (base.GetDocumentationTypes (assembly, forTypes, seen));
2817 IEnumerable<TypeDefinition> GetDocumentationTypes (AssemblyDefinition assembly, List<string> forTypes, HashSet<string> seen)
2820 while (ecmadocs.Read ()) {
2821 switch (ecmadocs.Name) {
2823 if (typeDepth == -1)
2824 typeDepth = ecmadocs.Depth;
2825 if (ecmadocs.NodeType != XmlNodeType.Element)
2827 if (typeDepth != ecmadocs.Depth) // nested <TypeDefinition/> element?
2829 string typename = ecmadocs.GetAttribute ("FullName");
2830 string typename2 = MDocUpdater.GetTypeFileName (typename);
2831 if (forTypes != null &&
2832 forTypes.BinarySearch (typename) < 0 &&
2833 typename != typename2 &&
2834 forTypes.BinarySearch (typename2) < 0)
2837 if ((t = assembly.GetType (typename)) == null &&
2838 (t = assembly.GetType (typename2)) == null)
2840 seen.Add (typename);
2841 if (typename != typename2)
2842 seen.Add (typename2);
2843 Console.WriteLine (" Import: {0}", t.FullName);
2844 if (ecmadocs.Name != "Docs") {
2845 int depth = ecmadocs.Depth;
2846 while (ecmadocs.Read ()) {
2847 if (ecmadocs.Name == "Docs" && ecmadocs.Depth == depth + 1)
2851 if (!ecmadocs.IsStartElement ("Docs"))
2852 throw new InvalidOperationException ("Found " + ecmadocs.Name + "; expecting <Docs/>!");
2862 public override IEnumerable<DocsNodeInfo> GetDocumentationMembers (XmlDocument basefile, TypeDefinition type)
2864 return GetMembers (basefile, type)
2865 .Concat (base.GetDocumentationMembers (basefile, type));
2868 private IEnumerable<DocsNodeInfo> GetMembers (XmlDocument basefile, TypeDefinition type)
2870 while (ecmadocs.Name != "Members" && ecmadocs.Read ()) {
2873 if (ecmadocs.IsEmptyElement)
2876 int membersDepth = ecmadocs.Depth;
2878 while (go && ecmadocs.Read ()) {
2879 switch (ecmadocs.Name) {
2881 if (membersDepth != ecmadocs.Depth - 1 || ecmadocs.NodeType != XmlNodeType.Element)
2883 DocumentationMember dm = new DocumentationMember (ecmadocs);
2884 string xp = MDocUpdater.GetXPathForMember (dm);
2885 XmlElement oldmember = (XmlElement) basefile.SelectSingleNode (xp);
2887 if (oldmember == null) {
2888 m = GetMember (type, dm);
2890 app.Warning ("Could not import ECMA docs for `{0}'s `{1}': Member not found.",
2891 type.FullName, dm.MemberSignatures ["C#"]);
2892 // SelectSingleNode (ecmaDocsMember, "MemberSignature[@Language=\"C#\"]/@Value").Value);
2895 // oldmember lookup may have failed due to type parameter renames.
2897 oldmember = (XmlElement) basefile.SelectSingleNode (MDocUpdater.GetXPathForMember (m));
2898 if (oldmember == null) {
2899 XmlElement members = MDocUpdater.WriteElement (basefile.DocumentElement, "Members");
2900 oldmember = basefile.CreateElement ("Member");
2901 oldmember.SetAttribute ("MemberName", dm.MemberName);
2902 members.AppendChild (oldmember);
2903 foreach (string key in MDocUpdater.Sort (dm.MemberSignatures.Keys)) {
2904 XmlElement ms = basefile.CreateElement ("MemberSignature");
2905 ms.SetAttribute ("Language", key);
2906 ms.SetAttribute ("Value", (string) dm.MemberSignatures [key]);
2907 oldmember.AppendChild (ms);
2909 oldmember.SetAttribute ("__monodocer-seen__", "true");
2910 Console.WriteLine ("Member Added: {0}", oldmember.SelectSingleNode("MemberSignature[@Language='C#']/@Value").InnerText);
2915 m = GetMember (type, new DocumentationMember (oldmember));
2917 app.Warning ("Could not import ECMA docs for `{0}'s `{1}': Member not found.",
2918 type.FullName, dm.MemberSignatures ["C#"]);
2921 oldmember.SetAttribute ("__monodocer-seen__", "true");
2923 DocsNodeInfo node = new DocsNodeInfo (oldmember, m);
2924 if (ecmadocs.Name != "Docs")
2925 throw new InvalidOperationException ("Found " + ecmadocs.Name + "; expected <Docs/>!");
2930 if (membersDepth == ecmadocs.Depth && ecmadocs.NodeType == XmlNodeType.EndElement) {
2939 abstract class DocumentationImporter {
2941 public abstract void ImportDocumentation (DocsNodeInfo info);
2944 class MsxdocDocumentationImporter : DocumentationImporter {
2946 XmlDocument slashdocs;
2948 public MsxdocDocumentationImporter (string file)
2950 var xml = File.ReadAllText (file);
2952 // Ensure Unix line endings
2953 xml = xml.Replace ("\r", "");
2955 slashdocs = new XmlDocument();
2956 slashdocs.LoadXml (xml);
2959 public override void ImportDocumentation (DocsNodeInfo info)
2961 XmlNode elem = GetDocs (info.Member ?? info.Type);
2966 XmlElement e = info.Node;
2968 if (elem.SelectSingleNode("summary") != null)
2969 MDocUpdater.ClearElement(e, "summary");
2970 if (elem.SelectSingleNode("remarks") != null)
2971 MDocUpdater.ClearElement(e, "remarks");
2972 if (elem.SelectSingleNode ("value") != null || elem.SelectSingleNode ("returns") != null) {
2973 MDocUpdater.ClearElement(e, "value");
2974 MDocUpdater.ClearElement(e, "returns");
2977 foreach (XmlNode child in elem.ChildNodes) {
2978 switch (child.Name) {
2981 XmlAttribute name = child.Attributes ["name"];
2984 XmlElement p2 = (XmlElement) e.SelectSingleNode (child.Name + "[@name='" + name.Value + "']");
2986 p2.InnerXml = child.InnerXml;
2989 // Occasionally XML documentation will use <returns/> on
2990 // properties, so let's try to normalize things.
2993 XmlElement v = e.OwnerDocument.CreateElement (info.ReturnIsReturn ? "returns" : "value");
2994 v.InnerXml = child.InnerXml;
3000 case "permission": {
3001 XmlAttribute cref = child.Attributes ["cref"] ?? child.Attributes ["name"];
3004 XmlElement a = (XmlElement) e.SelectSingleNode (child.Name + "[@cref='" + cref.Value + "']");
3006 a = e.OwnerDocument.CreateElement (child.Name);
3007 a.SetAttribute ("cref", child.Attributes ["cref"].Value);
3010 a.InnerXml = child.InnerXml;
3014 XmlAttribute cref = child.Attributes ["cref"];
3017 XmlElement a = (XmlElement) e.SelectSingleNode ("altmember[@cref='" + cref.Value + "']");
3019 a = e.OwnerDocument.CreateElement ("altmember");
3020 a.SetAttribute ("cref", child.Attributes ["cref"].Value);
3027 if (child.NodeType == XmlNodeType.Element &&
3028 e.SelectNodes (child.Name).Cast<XmlElement>().Any (n => n.OuterXml == child.OuterXml))
3031 MDocUpdater.CopyNode (child, e);
3038 private XmlNode GetDocs (MemberReference member)
3040 string slashdocsig = MDocUpdater.slashdocFormatter.GetDeclaration (member);
3041 if (slashdocsig != null)
3042 return slashdocs.SelectSingleNode ("doc/members/member[@name='" + slashdocsig + "']");
3047 class EcmaDocumentationImporter : DocumentationImporter {
3051 public EcmaDocumentationImporter (XmlReader ecmaDocs)
3053 this.ecmadocs = ecmaDocs;
3056 public override void ImportDocumentation (DocsNodeInfo info)
3058 if (!ecmadocs.IsStartElement ("Docs")) {
3062 XmlElement e = info.Node;
3064 int depth = ecmadocs.Depth;
3065 ecmadocs.ReadStartElement ("Docs");
3066 while (ecmadocs.Read ()) {
3067 if (ecmadocs.Name == "Docs") {
3068 if (ecmadocs.Depth == depth && ecmadocs.NodeType == XmlNodeType.EndElement)
3071 throw new InvalidOperationException ("Skipped past current <Docs/> element!");
3073 if (!ecmadocs.IsStartElement ())
3075 switch (ecmadocs.Name) {
3078 string name = ecmadocs.GetAttribute ("name");
3081 XmlNode doc = e.SelectSingleNode (
3082 ecmadocs.Name + "[@name='" + name + "']");
3083 string value = ecmadocs.ReadInnerXml ();
3085 doc.InnerXml = value.Replace ("\r", "");
3092 string name = ecmadocs.Name;
3093 string cref = ecmadocs.GetAttribute ("cref");
3096 XmlNode doc = e.SelectSingleNode (
3097 ecmadocs.Name + "[@cref='" + cref + "']");
3098 string value = ecmadocs.ReadInnerXml ().Replace ("\r", "");
3100 doc.InnerXml = value;
3102 XmlElement n = e.OwnerDocument.CreateElement (name);
3103 n.SetAttribute ("cref", cref);
3110 string name = ecmadocs.Name;
3111 string xpath = ecmadocs.Name;
3112 StringList attributes = new StringList (ecmadocs.AttributeCount);
3113 if (ecmadocs.MoveToFirstAttribute ()) {
3115 attributes.Add ("@" + ecmadocs.Name + "=\"" + ecmadocs.Value + "\"");
3116 } while (ecmadocs.MoveToNextAttribute ());
3117 ecmadocs.MoveToContent ();
3119 if (attributes.Count > 0) {
3120 xpath += "[" + string.Join (" and ", attributes.ToArray ()) + "]";
3122 XmlNode doc = e.SelectSingleNode (xpath);
3123 string value = ecmadocs.ReadInnerXml ().Replace ("\r", "");
3125 doc.InnerXml = value;
3128 XmlElement n = e.OwnerDocument.CreateElement (name);
3130 foreach (string a in attributes) {
3131 int eq = a.IndexOf ('=');
3132 n.SetAttribute (a.Substring (1, eq-1), a.Substring (eq+2, a.Length-eq-3));
3143 class DocumentationMember {
3144 public StringToStringMap MemberSignatures = new StringToStringMap ();
3145 public string ReturnType;
3146 public StringList Parameters;
3147 public string MemberName;
3148 public string MemberType;
3150 public DocumentationMember (XmlReader reader)
3152 MemberName = reader.GetAttribute ("MemberName");
3153 int depth = reader.Depth;
3155 StringList p = new StringList ();
3157 if (reader.NodeType != XmlNodeType.Element)
3159 switch (reader.Name) {
3160 case "MemberSignature":
3161 MemberSignatures [reader.GetAttribute ("Language")] = reader.GetAttribute ("Value");
3164 MemberType = reader.ReadElementString ();
3167 if (reader.Depth == depth + 2)
3168 ReturnType = reader.ReadElementString ();
3171 if (reader.Depth == depth + 2)
3172 p.Add (reader.GetAttribute ("Type"));
3175 if (reader.Depth == depth + 1)
3179 } while (go && reader.Read () && reader.Depth >= depth);
3185 public DocumentationMember (XmlNode node)
3187 MemberName = node.Attributes ["MemberName"].Value;
3188 foreach (XmlNode n in node.SelectNodes ("MemberSignature")) {
3189 XmlAttribute l = n.Attributes ["Language"];
3190 XmlAttribute v = n.Attributes ["Value"];
3191 if (l != null && v != null)
3192 MemberSignatures [l.Value] = v.Value;
3194 MemberType = node.SelectSingleNode ("MemberType").InnerText;
3195 XmlNode rt = node.SelectSingleNode ("ReturnValue/ReturnType");
3197 ReturnType = rt.InnerText;
3198 XmlNodeList p = node.SelectNodes ("Parameters/Parameter");
3200 Parameters = new StringList (p.Count);
3201 for (int i = 0; i < p.Count; ++i)
3202 Parameters.Add (p [i].Attributes ["Type"].Value);
3207 public enum MemberFormatterState {
3210 WithinGenericTypeParameters,
3213 public abstract class MemberFormatter {
3215 public virtual string Language {
3219 public virtual string GetName (MemberReference member)
3221 TypeReference type = member as TypeReference;
3223 return GetTypeName (type);
3224 MethodReference method = member as MethodReference;
3225 if (method != null && method.Name == ".ctor") // method.IsConstructor
3226 return GetConstructorName (method);
3228 return GetMethodName (method);
3229 PropertyReference prop = member as PropertyReference;
3231 return GetPropertyName (prop);
3232 FieldReference field = member as FieldReference;
3234 return GetFieldName (field);
3235 EventReference e = member as EventReference;
3237 return GetEventName (e);
3238 throw new NotSupportedException ("Can't handle: " +
3239 (member == null ? "null" : member.GetType().ToString()));
3242 protected virtual string GetTypeName (TypeReference type)
3245 throw new ArgumentNullException ("type");
3246 return _AppendTypeName (new StringBuilder (type.Name.Length), type).ToString ();
3249 protected virtual char[] ArrayDelimeters {
3250 get {return new char[]{'[', ']'};}
3253 protected virtual MemberFormatterState MemberFormatterState { get; set; }
3255 protected StringBuilder _AppendTypeName (StringBuilder buf, TypeReference type)
3257 if (type is ArrayType) {
3258 TypeSpecification spec = type as TypeSpecification;
3259 _AppendTypeName (buf, spec != null ? spec.ElementType : type.GetElementType ())
3260 .Append (ArrayDelimeters [0]);
3261 var origState = MemberFormatterState;
3262 MemberFormatterState = MemberFormatterState.WithinArray;
3263 ArrayType array = (ArrayType) type;
3264 int rank = array.Rank;
3266 buf.Append (new string (',', rank-1));
3267 MemberFormatterState = origState;
3268 return buf.Append (ArrayDelimeters [1]);
3270 if (type is ByReferenceType) {
3271 return AppendRefTypeName (buf, type);
3273 if (type is PointerType) {
3274 return AppendPointerTypeName (buf, type);
3276 AppendNamespace (buf, type);
3277 if (type is GenericParameter) {
3278 return AppendTypeName (buf, type);
3280 GenericInstanceType genInst = type as GenericInstanceType;
3281 if (type.GenericParameters.Count == 0 &&
3282 (genInst == null ? true : genInst.GenericArguments.Count == 0)) {
3283 return AppendFullTypeName (buf, type);
3285 return AppendGenericType (buf, type);
3288 protected virtual StringBuilder AppendNamespace (StringBuilder buf, TypeReference type)
3290 string ns = DocUtils.GetNamespace (type);
3291 if (ns != null && ns.Length > 0)
3292 buf.Append (ns).Append ('.');
3296 protected virtual StringBuilder AppendFullTypeName (StringBuilder buf, TypeReference type)
3298 if (type.DeclaringType != null)
3299 AppendFullTypeName (buf, type.DeclaringType).Append (NestedTypeSeparator);
3300 return AppendTypeName (buf, type);
3303 protected virtual StringBuilder AppendTypeName (StringBuilder buf, TypeReference type)
3305 return AppendTypeName (buf, type.Name);
3308 protected virtual StringBuilder AppendTypeName (StringBuilder buf, string typename)
3310 int n = typename.IndexOf ("`");
3312 return buf.Append (typename.Substring (0, n));
3313 return buf.Append (typename);
3316 protected virtual string RefTypeModifier {
3320 protected virtual StringBuilder AppendRefTypeName (StringBuilder buf, TypeReference type)
3322 TypeSpecification spec = type as TypeSpecification;
3323 return _AppendTypeName (buf, spec != null ? spec.ElementType : type.GetElementType ())
3324 .Append (RefTypeModifier);
3327 protected virtual string PointerModifier {
3331 protected virtual StringBuilder AppendPointerTypeName (StringBuilder buf, TypeReference type)
3333 TypeSpecification spec = type as TypeSpecification;
3334 return _AppendTypeName (buf, spec != null ? spec.ElementType : type.GetElementType ())
3335 .Append (PointerModifier);
3338 protected virtual char[] GenericTypeContainer {
3339 get {return new char[]{'<', '>'};}
3342 protected virtual char NestedTypeSeparator {
3346 protected virtual StringBuilder AppendGenericType (StringBuilder buf, TypeReference type)
3348 List<TypeReference> decls = DocUtils.GetDeclaringTypes (
3349 type is GenericInstanceType ? type.GetElementType () : type);
3350 List<TypeReference> genArgs = GetGenericArguments (type);
3353 bool insertNested = false;
3354 foreach (var decl in decls) {
3355 TypeReference declDef = decl.Resolve () ?? decl;
3357 buf.Append (NestedTypeSeparator);
3359 insertNested = true;
3360 AppendTypeName (buf, declDef);
3361 int ac = DocUtils.GetGenericArgumentCount (declDef);
3365 buf.Append (GenericTypeContainer [0]);
3366 var origState = MemberFormatterState;
3367 MemberFormatterState = MemberFormatterState.WithinGenericTypeParameters;
3368 _AppendTypeName (buf, genArgs [argIdx++]);
3369 for (int i = 1; i < c; ++i)
3370 _AppendTypeName (buf.Append (","), genArgs [argIdx++]);
3371 MemberFormatterState = origState;
3372 buf.Append (GenericTypeContainer [1]);
3378 protected List<TypeReference> GetGenericArguments (TypeReference type)
3380 var args = new List<TypeReference> ();
3381 GenericInstanceType inst = type as GenericInstanceType;
3383 args.AddRange (inst.GenericArguments.Cast<TypeReference> ());
3385 args.AddRange (type.GenericParameters.Cast<TypeReference> ());
3389 protected virtual StringBuilder AppendGenericTypeConstraints (StringBuilder buf, TypeReference type)
3394 protected virtual string GetConstructorName (MethodReference constructor)
3396 return constructor.Name;
3399 protected virtual string GetMethodName (MethodReference method)
3404 protected virtual string GetPropertyName (PropertyReference property)
3406 return property.Name;
3409 protected virtual string GetFieldName (FieldReference field)
3414 protected virtual string GetEventName (EventReference e)
3419 public virtual string GetDeclaration (MemberReference member)
3422 throw new ArgumentNullException ("member");
3423 TypeDefinition type = member as TypeDefinition;
3425 return GetTypeDeclaration (type);
3426 MethodDefinition method = member as MethodDefinition;
3427 if (method != null && method.IsConstructor)
3428 return GetConstructorDeclaration (method);
3430 return GetMethodDeclaration (method);
3431 PropertyDefinition prop = member as PropertyDefinition;
3433 return GetPropertyDeclaration (prop);
3434 FieldDefinition field = member as FieldDefinition;
3436 return GetFieldDeclaration (field);
3437 EventDefinition e = member as EventDefinition;
3439 return GetEventDeclaration (e);
3440 throw new NotSupportedException ("Can't handle: " + member.GetType().ToString());
3443 protected virtual string GetTypeDeclaration (TypeDefinition type)
3446 throw new ArgumentNullException ("type");
3447 StringBuilder buf = new StringBuilder (type.Name.Length);
3448 _AppendTypeName (buf, type);
3449 AppendGenericTypeConstraints (buf, type);
3450 return buf.ToString ();
3453 protected virtual string GetConstructorDeclaration (MethodDefinition constructor)
3455 return GetConstructorName (constructor);
3458 protected virtual string GetMethodDeclaration (MethodDefinition method)
3460 // Special signature for destructors.
3461 if (method.Name == "Finalize" && method.Parameters.Count == 0)
3462 return GetFinalizerName (method);
3464 StringBuilder buf = new StringBuilder ();
3466 AppendVisibility (buf, method);
3467 if (buf.Length == 0 &&
3468 !(DocUtils.IsExplicitlyImplemented (method) && !method.IsSpecialName))
3471 AppendModifiers (buf, method);
3473 if (buf.Length != 0)
3475 buf.Append (GetTypeName (method.MethodReturnType)).Append (" ");
3477 AppendMethodName (buf, method);
3478 AppendGenericMethod (buf, method).Append (" ");
3479 AppendParameters (buf, method, method.Parameters);
3480 AppendGenericMethodConstraints (buf, method);
3481 return buf.ToString ();
3484 protected virtual string GetTypeName (MethodReturnType returnType)
3486 return GetName (returnType.ReturnType);
3489 protected virtual StringBuilder AppendMethodName (StringBuilder buf, MethodDefinition method)
3491 return buf.Append (method.Name);
3494 protected virtual string GetFinalizerName (MethodDefinition method)
3499 protected virtual StringBuilder AppendVisibility (StringBuilder buf, MethodDefinition method)
3504 protected virtual StringBuilder AppendModifiers (StringBuilder buf, MethodDefinition method)
3509 protected virtual StringBuilder AppendGenericMethod (StringBuilder buf, MethodDefinition method)
3514 protected virtual StringBuilder AppendParameters (StringBuilder buf, MethodDefinition method, IList<ParameterDefinition> parameters)
3519 protected virtual StringBuilder AppendGenericMethodConstraints (StringBuilder buf, MethodDefinition method)
3524 protected virtual string GetPropertyDeclaration (PropertyDefinition property)
3526 return GetPropertyName (property);
3529 protected virtual string GetFieldDeclaration (FieldDefinition field)
3531 return GetFieldName (field);
3534 protected virtual string GetEventDeclaration (EventDefinition e)
3536 return GetEventName (e);
3540 class ILFullMemberFormatter : MemberFormatter {
3542 public override string Language {
3543 get {return "ILAsm";}
3546 protected override char NestedTypeSeparator {
3552 protected override StringBuilder AppendNamespace (StringBuilder buf, TypeReference type)
3554 if (GetBuiltinType (type.FullName) != null)
3556 string ns = DocUtils.GetNamespace (type);
3557 if (ns != null && ns.Length > 0) {
3558 if (type.IsValueType)
3559 buf.Append ("valuetype ");
3561 buf.Append ("class ");
3562 buf.Append (ns).Append ('.');
3567 private static string GetBuiltinType (string t)
3570 case "System.Byte": return "unsigned int8";
3571 case "System.SByte": return "int8";
3572 case "System.Int16": return "int16";
3573 case "System.Int32": return "int32";
3574 case "System.Int64": return "int64";
3575 case "System.IntPtr": return "native int";
3577 case "System.UInt16": return "unsigned int16";
3578 case "System.UInt32": return "unsigned int32";
3579 case "System.UInt64": return "unsigned int64";
3580 case "System.UIntPtr": return "native unsigned int";
3582 case "System.Single": return "float32";
3583 case "System.Double": return "float64";
3584 case "System.Boolean": return "bool";
3585 case "System.Char": return "char";
3586 case "System.Void": return "void";
3587 case "System.String": return "string";
3588 case "System.Object": return "object";
3593 protected override StringBuilder AppendTypeName (StringBuilder buf, string typename)
3595 return buf.Append (typename);
3598 protected override StringBuilder AppendTypeName (StringBuilder buf, TypeReference type)
3600 var gp = type as GenericParameter;
3601 if (type is GenericParameter)
3602 return AppendGenericParameterConstraints (buf, (GenericParameter) type).Append (type.Name);
3604 string s = GetBuiltinType (type.FullName);
3606 return buf.Append (s);
3607 return base.AppendTypeName (buf, type);
3610 private StringBuilder AppendGenericParameterConstraints (StringBuilder buf, GenericParameter type)
3612 if (MemberFormatterState != MemberFormatterState.WithinGenericTypeParameters) {
3613 return buf.Append (type.Owner is TypeReference ? "!" : "!!");
3615 GenericParameterAttributes attrs = type.Attributes;
3616 if ((attrs & GenericParameterAttributes.ReferenceTypeConstraint) != 0)
3617 buf.Append ("class ");
3618 if ((attrs & GenericParameterAttributes.NotNullableValueTypeConstraint) != 0)
3619 buf.Append ("struct ");
3620 if ((attrs & GenericParameterAttributes.DefaultConstructorConstraint) != 0)
3621 buf.Append (".ctor ");
3622 IList<TypeReference> constraints = type.Constraints;
3623 MemberFormatterState = 0;
3624 if (constraints.Count > 0) {
3625 var full = new ILFullMemberFormatter ();
3626 buf.Append ("(").Append (full.GetName (constraints [0]));
3627 for (int i = 1; i < constraints.Count; ++i) {
3628 buf.Append (", ").Append (full.GetName (constraints [i]));
3632 MemberFormatterState = MemberFormatterState.WithinGenericTypeParameters;
3634 if ((attrs & GenericParameterAttributes.Covariant) != 0)
3636 if ((attrs & GenericParameterAttributes.Contravariant) != 0)
3641 protected override string GetTypeDeclaration (TypeDefinition type)
3643 string visibility = GetTypeVisibility (type.Attributes);
3644 if (visibility == null)
3647 StringBuilder buf = new StringBuilder ();
3649 buf.Append (".class ");
3651 buf.Append ("nested ");
3652 buf.Append (visibility).Append (" ");
3653 if (type.IsInterface)
3654 buf.Append ("interface ");
3655 if (type.IsSequentialLayout)
3656 buf.Append ("sequential ");
3657 if (type.IsAutoLayout)
3658 buf.Append ("auto ");
3659 if (type.IsAnsiClass)
3660 buf.Append ("ansi ");
3661 if (type.IsAbstract)
3662 buf.Append ("abstract ");
3663 if (type.IsSerializable)
3664 buf.Append ("serializable ");
3666 buf.Append ("sealed ");
3667 if (type.IsBeforeFieldInit)
3668 buf.Append ("beforefieldinit ");
3669 var state = MemberFormatterState;
3670 MemberFormatterState = MemberFormatterState.WithinGenericTypeParameters;
3671 buf.Append (GetName (type));
3672 MemberFormatterState = state;
3673 var full = new ILFullMemberFormatter ();
3674 if (type.BaseType != null) {
3675 buf.Append (" extends ");
3676 if (type.BaseType.FullName == "System.Object")
3677 buf.Append ("System.Object");
3679 buf.Append (full.GetName (type.BaseType).Substring ("class ".Length));
3682 foreach (var name in type.Interfaces
3683 .Select (i => full.GetName (i))
3684 .OrderBy (n => n)) {
3686 buf.Append (" implements ");
3695 return buf.ToString ();
3698 protected override StringBuilder AppendGenericType (StringBuilder buf, TypeReference type)
3700 List<TypeReference> decls = DocUtils.GetDeclaringTypes (
3701 type is GenericInstanceType ? type.GetElementType () : type);
3703 foreach (var decl in decls) {
3704 TypeReference declDef = decl.Resolve () ?? decl;
3706 buf.Append (NestedTypeSeparator);
3709 AppendTypeName (buf, declDef);
3713 foreach (TypeReference arg in GetGenericArguments (type)) {
3717 _AppendTypeName (buf, arg);
3723 static string GetTypeVisibility (TypeAttributes ta)
3725 switch (ta & TypeAttributes.VisibilityMask) {
3726 case TypeAttributes.Public:
3727 case TypeAttributes.NestedPublic:
3730 case TypeAttributes.NestedFamily:
3731 case TypeAttributes.NestedFamORAssem:
3739 protected override string GetConstructorDeclaration (MethodDefinition constructor)
3741 return GetMethodDeclaration (constructor);
3744 protected override string GetMethodDeclaration (MethodDefinition method)
3746 if (method.IsPrivate && !DocUtils.IsExplicitlyImplemented (method))
3749 var buf = new StringBuilder ();
3750 buf.Append (".method ");
3751 AppendVisibility (buf, method);
3752 if (method.IsStatic)
3753 buf.Append ("static ");
3754 if (method.IsHideBySig)
3755 buf.Append ("hidebysig ");
3756 if (method.IsPInvokeImpl) {
3757 var info = method.PInvokeInfo;
3758 buf.Append ("pinvokeimpl (\"")
3759 .Append (info.Module.Name)
3760 .Append ("\" as \"")
3761 .Append (info.EntryPoint)
3763 if (info.IsCharSetAuto)
3764 buf.Append (" auto");
3765 if (info.IsCharSetUnicode)
3766 buf.Append (" unicode");
3767 if (info.IsCharSetAnsi)
3768 buf.Append (" ansi");
3769 if (info.IsCallConvCdecl)
3770 buf.Append (" cdecl");
3771 if (info.IsCallConvStdCall)
3772 buf.Append (" stdcall");
3773 if (info.IsCallConvWinapi)
3774 buf.Append (" winapi");
3775 if (info.IsCallConvThiscall)
3776 buf.Append (" thiscall");
3777 if (info.SupportsLastError)
3778 buf.Append (" lasterr");
3781 if (method.IsSpecialName)
3782 buf.Append ("specialname ");
3783 if (method.IsRuntimeSpecialName)
3784 buf.Append ("rtspecialname ");
3785 if (method.IsNewSlot)
3786 buf.Append ("newslot ");
3787 if (method.IsVirtual)
3788 buf.Append ("virtual ");
3789 if (!method.IsStatic)
3790 buf.Append ("instance ");
3791 _AppendTypeName (buf, method.ReturnType);
3793 .Append (method.Name);
3794 if (method.IsGenericMethod ()) {
3795 var state = MemberFormatterState;
3796 MemberFormatterState = MemberFormatterState.WithinGenericTypeParameters;
3797 IList<GenericParameter> args = method.GenericParameters;
3798 if (args.Count > 0) {
3800 _AppendTypeName (buf, args [0]);
3801 for (int i = 1; i < args.Count; ++i)
3802 _AppendTypeName (buf.Append (", "), args [i]);
3805 MemberFormatterState = state;
3810 for (int i = 0; i < method.Parameters.Count; ++i) {
3814 _AppendTypeName (buf, method.Parameters [i].ParameterType);
3816 buf.Append (method.Parameters [i].Name);
3820 buf.Append (" cil");
3821 if (method.IsRuntime)
3822 buf.Append (" runtime");
3823 if (method.IsManaged)
3824 buf.Append (" managed");
3826 return buf.ToString ();
3829 protected override StringBuilder AppendMethodName (StringBuilder buf, MethodDefinition method)
3831 if (DocUtils.IsExplicitlyImplemented (method)) {
3832 TypeReference iface;
3833 MethodReference ifaceMethod;
3834 DocUtils.GetInfoForExplicitlyImplementedMethod (method, out iface, out ifaceMethod);
3835 return buf.Append (new CSharpMemberFormatter ().GetName (iface))
3837 .Append (ifaceMethod.Name);
3839 return base.AppendMethodName (buf, method);
3842 protected override string RefTypeModifier {
3846 protected override StringBuilder AppendVisibility (StringBuilder buf, MethodDefinition method)
3848 if (method.IsPublic)
3849 return buf.Append ("public ");
3850 if (method.IsFamilyAndAssembly)
3851 return buf.Append ("familyandassembly");
3852 if (method.IsFamilyOrAssembly)
3853 return buf.Append ("familyorassembly");
3854 if (method.IsFamily)
3855 return buf.Append ("family");
3859 protected override StringBuilder AppendModifiers (StringBuilder buf, MethodDefinition method)
3861 string modifiers = String.Empty;
3862 if (method.IsStatic) modifiers += " static";
3863 if (method.IsVirtual && !method.IsAbstract) {
3864 if ((method.Attributes & MethodAttributes.NewSlot) != 0) modifiers += " virtual";
3865 else modifiers += " override";
3867 TypeDefinition declType = (TypeDefinition) method.DeclaringType;
3868 if (method.IsAbstract && !declType.IsInterface) modifiers += " abstract";
3869 if (method.IsFinal) modifiers += " sealed";
3870 if (modifiers == " virtual sealed") modifiers = "";
3872 return buf.Append (modifiers);
3875 protected override StringBuilder AppendGenericMethod (StringBuilder buf, MethodDefinition method)
3877 if (method.IsGenericMethod ()) {
3878 IList<GenericParameter> args = method.GenericParameters;
3879 if (args.Count > 0) {
3881 buf.Append (args [0].Name);
3882 for (int i = 1; i < args.Count; ++i)
3883 buf.Append (",").Append (args [i].Name);
3890 protected override StringBuilder AppendParameters (StringBuilder buf, MethodDefinition method, IList<ParameterDefinition> parameters)
3892 return AppendParameters (buf, method, parameters, '(', ')');
3895 private StringBuilder AppendParameters (StringBuilder buf, MethodDefinition method, IList<ParameterDefinition> parameters, char begin, char end)
3899 if (parameters.Count > 0) {
3900 if (DocUtils.IsExtensionMethod (method))
3901 buf.Append ("this ");
3902 AppendParameter (buf, parameters [0]);
3903 for (int i = 1; i < parameters.Count; ++i) {
3905 AppendParameter (buf, parameters [i]);
3909 return buf.Append (end);
3912 private StringBuilder AppendParameter (StringBuilder buf, ParameterDefinition parameter)
3914 if (parameter.ParameterType is ByReferenceType) {
3915 if (parameter.IsOut)
3916 buf.Append ("out ");
3918 buf.Append ("ref ");
3920 buf.Append (GetName (parameter.ParameterType)).Append (" ");
3921 return buf.Append (parameter.Name);
3924 protected override string GetPropertyDeclaration (PropertyDefinition property)
3926 MethodDefinition gm = null, sm = null;
3928 string get_visible = null;
3929 if ((gm = property.GetMethod) != null &&
3930 (DocUtils.IsExplicitlyImplemented (gm) ||
3931 (!gm.IsPrivate && !gm.IsAssembly && !gm.IsFamilyAndAssembly)))
3932 get_visible = AppendVisibility (new StringBuilder (), gm).ToString ();
3933 string set_visible = null;
3934 if ((sm = property.SetMethod) != null &&
3935 (DocUtils.IsExplicitlyImplemented (sm) ||
3936 (!sm.IsPrivate && !sm.IsAssembly && !sm.IsFamilyAndAssembly)))
3937 set_visible = AppendVisibility (new StringBuilder (), sm).ToString ();
3939 if ((set_visible == null) && (get_visible == null))
3943 StringBuilder buf = new StringBuilder ()
3944 .Append (".property ");
3945 if (!(gm ?? sm).IsStatic)
3946 buf.Append ("instance ");
3947 _AppendTypeName (buf, property.PropertyType);
3948 buf.Append (' ').Append (property.Name);
3949 if (!property.HasParameters || property.Parameters.Count == 0)
3950 return buf.ToString ();
3954 foreach (ParameterDefinition p in property.Parameters) {
3958 _AppendTypeName (buf, p.ParameterType);
3962 return buf.ToString ();
3965 protected override string GetFieldDeclaration (FieldDefinition field)
3967 TypeDefinition declType = (TypeDefinition) field.DeclaringType;
3968 if (declType.IsEnum && field.Name == "value__")
3969 return null; // This member of enums aren't documented.
3971 StringBuilder buf = new StringBuilder ();
3972 AppendFieldVisibility (buf, field);
3973 if (buf.Length == 0)
3976 buf.Insert (0, ".field ");
3979 buf.Append ("static ");
3980 if (field.IsInitOnly)
3981 buf.Append ("initonly ");
3982 if (field.IsLiteral)
3983 buf.Append ("literal ");
3984 _AppendTypeName (buf, field.FieldType);
3985 buf.Append (' ').Append (field.Name);
3986 AppendFieldValue (buf, field);
3988 return buf.ToString ();
3991 static StringBuilder AppendFieldVisibility (StringBuilder buf, FieldDefinition field)
3994 return buf.Append ("public ");
3995 if (field.IsFamilyAndAssembly)
3996 return buf.Append ("familyandassembly ");
3997 if (field.IsFamilyOrAssembly)
3998 return buf.Append ("familyorassembly ");
4000 return buf.Append ("family ");
4004 static StringBuilder AppendFieldValue (StringBuilder buf, FieldDefinition field)
4006 // enums have a value__ field, which we ignore
4007 if (field.DeclaringType.IsGenericType ())
4009 if (field.HasConstant && field.IsLiteral) {
4012 val = field.Constant;
4017 buf.Append (" = ").Append ("null");
4018 else if (val is Enum)
4020 .Append (GetBuiltinType (field.DeclaringType.GetUnderlyingType ().FullName))
4022 .Append (val.ToString ())
4024 else if (val is IFormattable) {
4025 string value = ((IFormattable)val).ToString();
4028 buf.Append ("\"" + value + "\"");
4030 buf.Append (GetBuiltinType (field.DeclaringType.GetUnderlyingType ().FullName))
4039 protected override string GetEventDeclaration (EventDefinition e)
4041 StringBuilder buf = new StringBuilder ();
4042 if (AppendVisibility (buf, e.AddMethod).Length == 0) {
4047 buf.Append (".event ")
4048 .Append (GetName (e.EventType))
4052 return buf.ToString ();
4056 class ILMemberFormatter : ILFullMemberFormatter {
4057 protected override StringBuilder AppendNamespace (StringBuilder buf, TypeReference type)
4063 class CSharpFullMemberFormatter : MemberFormatter {
4065 public override string Language {
4069 protected override StringBuilder AppendNamespace (StringBuilder buf, TypeReference type)
4071 string ns = DocUtils.GetNamespace (type);
4072 if (GetCSharpType (type.FullName) == null && ns != null && ns.Length > 0 && ns != "System")
4073 buf.Append (ns).Append ('.');
4077 private string GetCSharpType (string t)
4080 case "System.Byte": return "byte";
4081 case "System.SByte": return "sbyte";
4082 case "System.Int16": return "short";
4083 case "System.Int32": return "int";
4084 case "System.Int64": return "long";
4086 case "System.UInt16": return "ushort";
4087 case "System.UInt32": return "uint";
4088 case "System.UInt64": return "ulong";
4090 case "System.Single": return "float";
4091 case "System.Double": return "double";
4092 case "System.Decimal": return "decimal";
4093 case "System.Boolean": return "bool";
4094 case "System.Char": return "char";
4095 case "System.Void": return "void";
4096 case "System.String": return "string";
4097 case "System.Object": return "object";
4102 protected override StringBuilder AppendTypeName (StringBuilder buf, TypeReference type)
4104 if (type is GenericParameter)
4105 return AppendGenericParameterConstraints (buf, (GenericParameter) type).Append (type.Name);
4106 string t = type.FullName;
4107 if (!t.StartsWith ("System.")) {
4108 return base.AppendTypeName (buf, type);
4111 string s = GetCSharpType (t);
4113 return buf.Append (s);
4115 return base.AppendTypeName (buf, type);
4118 private StringBuilder AppendGenericParameterConstraints (StringBuilder buf, GenericParameter type)
4120 if (MemberFormatterState != MemberFormatterState.WithinGenericTypeParameters)
4122 GenericParameterAttributes attrs = type.Attributes;
4123 bool isout = (attrs & GenericParameterAttributes.Covariant) != 0;
4124 bool isin = (attrs & GenericParameterAttributes.Contravariant) != 0;
4128 buf.Append ("out ");
4132 protected override string GetTypeDeclaration (TypeDefinition type)
4134 string visibility = GetTypeVisibility (type.Attributes);
4135 if (visibility == null)
4138 StringBuilder buf = new StringBuilder ();
4140 buf.Append (visibility);
4143 MemberFormatter full = new CSharpFullMemberFormatter ();
4145 if (DocUtils.IsDelegate (type)) {
4146 buf.Append("delegate ");
4147 MethodDefinition invoke = type.GetMethod ("Invoke");
4148 buf.Append (full.GetName (invoke.ReturnType)).Append (" ");
4149 buf.Append (GetName (type));
4150 AppendParameters (buf, invoke, invoke.Parameters);
4151 AppendGenericTypeConstraints (buf, type);
4154 return buf.ToString();
4157 if (type.IsAbstract && !type.IsInterface)
4158 buf.Append("abstract ");
4159 if (type.IsSealed && !DocUtils.IsDelegate (type) && !type.IsValueType)
4160 buf.Append("sealed ");
4161 buf.Replace ("abstract sealed", "static");
4163 buf.Append (GetTypeKind (type));
4165 buf.Append (GetCSharpType (type.FullName) == null
4170 TypeReference basetype = type.BaseType;
4171 if (basetype != null && basetype.FullName == "System.Object" || type.IsValueType) // FIXME
4174 List<string> interface_names = DocUtils.GetUserImplementedInterfaces (type)
4175 .Select (iface => full.GetName (iface))
4179 if (basetype != null || interface_names.Count > 0)
4182 if (basetype != null) {
4183 buf.Append (full.GetName (basetype));
4184 if (interface_names.Count > 0)
4188 for (int i = 0; i < interface_names.Count; i++){
4191 buf.Append (interface_names [i]);
4193 AppendGenericTypeConstraints (buf, type);
4196 return buf.ToString ();
4199 static string GetTypeKind (TypeDefinition t)
4205 if (t.IsClass || t.FullName == "System.Enum")
4209 throw new ArgumentException(t.FullName);
4212 static string GetTypeVisibility (TypeAttributes ta)
4214 switch (ta & TypeAttributes.VisibilityMask) {
4215 case TypeAttributes.Public:
4216 case TypeAttributes.NestedPublic:
4219 case TypeAttributes.NestedFamily:
4220 case TypeAttributes.NestedFamORAssem:
4228 protected override StringBuilder AppendGenericTypeConstraints (StringBuilder buf, TypeReference type)
4230 if (type.GenericParameters.Count == 0)
4232 return AppendConstraints (buf, type.GenericParameters);
4235 private StringBuilder AppendConstraints (StringBuilder buf, IList<GenericParameter> genArgs)
4237 foreach (GenericParameter genArg in genArgs) {
4238 GenericParameterAttributes attrs = genArg.Attributes;
4239 IList<TypeReference> constraints = genArg.Constraints;
4240 if (attrs == GenericParameterAttributes.NonVariant && constraints.Count == 0)
4243 bool isref = (attrs & GenericParameterAttributes.ReferenceTypeConstraint) != 0;
4244 bool isvt = (attrs & GenericParameterAttributes.NotNullableValueTypeConstraint) != 0;
4245 bool isnew = (attrs & GenericParameterAttributes.DefaultConstructorConstraint) != 0;
4248 if (!isref && !isvt && !isnew && constraints.Count == 0)
4250 buf.Append (" where ").Append (genArg.Name).Append (" : ");
4252 buf.Append ("class");
4256 buf.Append ("struct");
4259 if (constraints.Count > 0 && !isvt) {
4262 buf.Append (GetTypeName (constraints [0]));
4263 for (int i = 1; i < constraints.Count; ++i)
4264 buf.Append (", ").Append (GetTypeName (constraints [i]));
4266 if (isnew && !isvt) {
4269 buf.Append ("new()");
4275 protected override string GetConstructorDeclaration (MethodDefinition constructor)
4277 StringBuilder buf = new StringBuilder ();
4278 AppendVisibility (buf, constructor);
4279 if (buf.Length == 0)
4283 base.AppendTypeName (buf, constructor.DeclaringType.Name).Append (' ');
4284 AppendParameters (buf, constructor, constructor.Parameters);
4287 return buf.ToString ();
4290 protected override string GetMethodDeclaration (MethodDefinition method)
4292 string decl = base.GetMethodDeclaration (method);
4298 protected override StringBuilder AppendMethodName (StringBuilder buf, MethodDefinition method)
4300 if (DocUtils.IsExplicitlyImplemented (method)) {
4301 TypeReference iface;
4302 MethodReference ifaceMethod;
4303 DocUtils.GetInfoForExplicitlyImplementedMethod (method, out iface, out ifaceMethod);
4304 return buf.Append (new CSharpMemberFormatter ().GetName (iface))
4306 .Append (ifaceMethod.Name);
4308 return base.AppendMethodName (buf, method);
4311 protected override StringBuilder AppendGenericMethodConstraints (StringBuilder buf, MethodDefinition method)
4313 if (method.GenericParameters.Count == 0)
4315 return AppendConstraints (buf, method.GenericParameters);
4318 protected override string RefTypeModifier {
4322 protected override string GetFinalizerName (MethodDefinition method)
4324 return "~" + method.DeclaringType.Name + " ()";
4327 protected override StringBuilder AppendVisibility (StringBuilder buf, MethodDefinition method)
4331 if (method.IsPublic)
4332 return buf.Append ("public");
4333 if (method.IsFamily || method.IsFamilyOrAssembly)
4334 return buf.Append ("protected");
4338 protected override StringBuilder AppendModifiers (StringBuilder buf, MethodDefinition method)
4340 string modifiers = String.Empty;
4341 if (method.IsStatic) modifiers += " static";
4342 if (method.IsVirtual && !method.IsAbstract) {
4343 if ((method.Attributes & MethodAttributes.NewSlot) != 0) modifiers += " virtual";
4344 else modifiers += " override";
4346 TypeDefinition declType = (TypeDefinition) method.DeclaringType;
4347 if (method.IsAbstract && !declType.IsInterface) modifiers += " abstract";
4348 if (method.IsFinal) modifiers += " sealed";
4349 if (modifiers == " virtual sealed") modifiers = "";
4351 return buf.Append (modifiers);
4354 protected override StringBuilder AppendGenericMethod (StringBuilder buf, MethodDefinition method)
4356 if (method.IsGenericMethod ()) {
4357 IList<GenericParameter> args = method.GenericParameters;
4358 if (args.Count > 0) {
4360 buf.Append (args [0].Name);
4361 for (int i = 1; i < args.Count; ++i)
4362 buf.Append (",").Append (args [i].Name);
4369 protected override StringBuilder AppendParameters (StringBuilder buf, MethodDefinition method, IList<ParameterDefinition> parameters)
4371 return AppendParameters (buf, method, parameters, '(', ')');
4374 private StringBuilder AppendParameters (StringBuilder buf, MethodDefinition method, IList<ParameterDefinition> parameters, char begin, char end)
4378 if (parameters.Count > 0) {
4379 if (DocUtils.IsExtensionMethod (method))
4380 buf.Append ("this ");
4381 AppendParameter (buf, parameters [0]);
4382 for (int i = 1; i < parameters.Count; ++i) {
4384 AppendParameter (buf, parameters [i]);
4388 return buf.Append (end);
4391 private StringBuilder AppendParameter (StringBuilder buf, ParameterDefinition parameter)
4393 if (parameter.ParameterType is ByReferenceType) {
4394 if (parameter.IsOut)
4395 buf.Append ("out ");
4397 buf.Append ("ref ");
4399 buf.Append (GetName (parameter.ParameterType)).Append (" ");
4400 return buf.Append (parameter.Name);
4403 protected override string GetPropertyDeclaration (PropertyDefinition property)
4405 MethodDefinition method;
4407 string get_visible = null;
4408 if ((method = property.GetMethod) != null &&
4409 (DocUtils.IsExplicitlyImplemented (method) ||
4410 (!method.IsPrivate && !method.IsAssembly && !method.IsFamilyAndAssembly)))
4411 get_visible = AppendVisibility (new StringBuilder (), method).ToString ();
4412 string set_visible = null;
4413 if ((method = property.SetMethod) != null &&
4414 (DocUtils.IsExplicitlyImplemented (method) ||
4415 (!method.IsPrivate && !method.IsAssembly && !method.IsFamilyAndAssembly)))
4416 set_visible = AppendVisibility (new StringBuilder (), method).ToString ();
4418 if ((set_visible == null) && (get_visible == null))
4422 StringBuilder buf = new StringBuilder ();
4423 if (get_visible != null && (set_visible == null || (set_visible != null && get_visible == set_visible)))
4424 buf.Append (visibility = get_visible);
4425 else if (set_visible != null && get_visible == null)
4426 buf.Append (visibility = set_visible);
4428 buf.Append (visibility = "public");
4430 // Pick an accessor to use for static/virtual/override/etc. checks.
4431 method = property.SetMethod;
4433 method = property.GetMethod;
4435 string modifiers = String.Empty;
4436 if (method.IsStatic) modifiers += " static";
4437 if (method.IsVirtual && !method.IsAbstract) {
4438 if ((method.Attributes & MethodAttributes.NewSlot) != 0)
4439 modifiers += " virtual";
4441 modifiers += " override";
4443 TypeDefinition declDef = (TypeDefinition) method.DeclaringType;
4444 if (method.IsAbstract && !declDef.IsInterface)
4445 modifiers += " abstract";
4447 modifiers += " sealed";
4448 if (modifiers == " virtual sealed")
4450 buf.Append (modifiers).Append (' ');
4452 buf.Append (GetName (property.PropertyType)).Append (' ');
4454 IEnumerable<MemberReference> defs = property.DeclaringType.GetDefaultMembers ();
4455 string name = property.Name;
4456 foreach (MemberReference mi in defs) {
4457 if (mi == property) {
4462 buf.Append (name == "this" ? name : DocUtils.GetPropertyName (property));
4464 if (property.Parameters.Count != 0) {
4465 AppendParameters (buf, method, property.Parameters, '[', ']');
4469 if (set_visible != null) {
4470 if (set_visible != visibility)
4471 buf.Append (' ').Append (set_visible);
4472 buf.Append (" set;");
4474 if (get_visible != null) {
4475 if (get_visible != visibility)
4476 buf.Append (' ').Append (get_visible);
4477 buf.Append (" get;");
4481 return buf [0] != ' ' ? buf.ToString () : buf.ToString (1, buf.Length-1);
4484 protected override string GetFieldDeclaration (FieldDefinition field)
4486 TypeDefinition declType = (TypeDefinition) field.DeclaringType;
4487 if (declType.IsEnum && field.Name == "value__")
4488 return null; // This member of enums aren't documented.
4490 StringBuilder buf = new StringBuilder ();
4491 AppendFieldVisibility (buf, field);
4492 if (buf.Length == 0)
4495 if (declType.IsEnum)
4498 if (field.IsStatic && !field.IsLiteral)
4499 buf.Append (" static");
4500 if (field.IsInitOnly)
4501 buf.Append (" readonly");
4502 if (field.IsLiteral)
4503 buf.Append (" const");
4505 buf.Append (' ').Append (GetName (field.FieldType)).Append (' ');
4506 buf.Append (field.Name);
4507 AppendFieldValue (buf, field);
4510 return buf.ToString ();
4513 static StringBuilder AppendFieldVisibility (StringBuilder buf, FieldDefinition field)
4516 return buf.Append ("public");
4517 if (field.IsFamily || field.IsFamilyOrAssembly)
4518 return buf.Append ("protected");
4522 static StringBuilder AppendFieldValue (StringBuilder buf, FieldDefinition field)
4524 // enums have a value__ field, which we ignore
4525 if (((TypeDefinition ) field.DeclaringType).IsEnum ||
4526 field.DeclaringType.IsGenericType ())
4528 if (field.HasConstant && field.IsLiteral) {
4531 val = field.Constant;
4536 buf.Append (" = ").Append ("null");
4537 else if (val is Enum)
4538 buf.Append (" = ").Append (val.ToString ());
4539 else if (val is IFormattable) {
4540 string value = ((IFormattable)val).ToString();
4542 value = "\"" + value + "\"";
4543 buf.Append (" = ").Append (value);
4549 protected override string GetEventDeclaration (EventDefinition e)
4551 StringBuilder buf = new StringBuilder ();
4552 if (AppendVisibility (buf, e.AddMethod).Length == 0) {
4556 AppendModifiers (buf, e.AddMethod);
4558 buf.Append (" event ");
4559 buf.Append (GetName (e.EventType)).Append (' ');
4560 buf.Append (e.Name).Append (';');
4562 return buf.ToString ();
4566 class CSharpMemberFormatter : CSharpFullMemberFormatter {
4567 protected override StringBuilder AppendNamespace (StringBuilder buf, TypeReference type)
4573 class DocTypeFullMemberFormatter : MemberFormatter {
4574 public static readonly MemberFormatter Default = new DocTypeFullMemberFormatter ();
4576 protected override char NestedTypeSeparator {
4581 class DocTypeMemberFormatter : DocTypeFullMemberFormatter {
4582 protected override StringBuilder AppendNamespace (StringBuilder buf, TypeReference type)
4588 class SlashDocMemberFormatter : MemberFormatter {
4590 protected override char[] GenericTypeContainer {
4591 get {return new char[]{'{', '}'};}
4594 private bool AddTypeCount = true;
4596 private TypeReference genDeclType;
4597 private MethodReference genDeclMethod;
4599 protected override StringBuilder AppendTypeName (StringBuilder buf, TypeReference type)
4601 if (type is GenericParameter) {
4603 if (genDeclType != null) {
4604 IList<GenericParameter> genArgs = genDeclType.GenericParameters;
4605 for (int i = 0; i < genArgs.Count; ++i) {
4606 if (genArgs [i].Name == type.Name) {
4607 buf.Append ('`').Append (i);
4612 if (genDeclMethod != null) {
4613 IList<GenericParameter> genArgs = null;
4614 if (genDeclMethod.IsGenericMethod ()) {
4615 genArgs = genDeclMethod.GenericParameters;
4616 for (int i = 0; i < genArgs.Count; ++i) {
4617 if (genArgs [i].Name == type.Name) {
4618 buf.Append ("``").Append (i);
4624 if (genDeclType == null && genDeclMethod == null) {
4625 // Probably from within an explicitly implemented interface member,
4626 // where CSC uses parameter names instead of indices (why?), e.g.
4627 // MyList`2.Mono#DocTest#Generic#IFoo{A}#Method``1(`0,``0) instead of
4628 // MyList`2.Mono#DocTest#Generic#IFoo{`0}#Method``1(`0,``0).
4629 buf.Append (type.Name);
4631 if (buf.Length == l) {
4632 throw new Exception (string.Format (
4633 "Unable to translate generic parameter {0}; genDeclType={1}, genDeclMethod={2}",
4634 type.Name, genDeclType, genDeclMethod));
4638 base.AppendTypeName (buf, type);
4640 int numArgs = type.GenericParameters.Count;
4641 if (type.DeclaringType != null)
4642 numArgs -= type.GenericParameters.Count;
4644 buf.Append ('`').Append (numArgs);
4651 protected override StringBuilder AppendGenericType (StringBuilder buf, TypeReference type)
4654 base.AppendGenericType (buf, type);
4656 AppendType (buf, type);
4660 private StringBuilder AppendType (StringBuilder buf, TypeReference type)
4662 List<TypeReference> decls = DocUtils.GetDeclaringTypes (type);
4663 bool insertNested = false;
4664 int prevParamCount = 0;
4665 foreach (var decl in decls) {
4667 buf.Append (NestedTypeSeparator);
4668 insertNested = true;
4669 base.AppendTypeName (buf, decl);
4670 int argCount = DocUtils.GetGenericArgumentCount (decl);
4671 int numArgs = argCount - prevParamCount;
4672 prevParamCount = argCount;
4674 buf.Append ('`').Append (numArgs);
4679 public override string GetDeclaration (MemberReference member)
4681 TypeReference r = member as TypeReference;
4683 return "T:" + GetTypeName (r);
4685 return base.GetDeclaration (member);
4688 protected override string GetConstructorName (MethodReference constructor)
4690 return GetMethodDefinitionName (constructor, "#ctor");
4693 protected override string GetMethodName (MethodReference method)
4696 MethodDefinition methodDef = method as MethodDefinition;
4697 if (methodDef == null || !DocUtils.IsExplicitlyImplemented (methodDef))
4700 TypeReference iface;
4701 MethodReference ifaceMethod;
4702 DocUtils.GetInfoForExplicitlyImplementedMethod (methodDef, out iface, out ifaceMethod);
4703 AddTypeCount = false;
4704 name = GetTypeName (iface) + "." + ifaceMethod.Name;
4705 AddTypeCount = true;
4707 return GetMethodDefinitionName (method, name);
4710 private string GetMethodDefinitionName (MethodReference method, string name)
4712 StringBuilder buf = new StringBuilder ();
4713 buf.Append (GetTypeName (method.DeclaringType));
4715 buf.Append (name.Replace (".", "#"));
4716 if (method.IsGenericMethod ()) {
4717 IList<GenericParameter> genArgs = method.GenericParameters;
4718 if (genArgs.Count > 0)
4719 buf.Append ("``").Append (genArgs.Count);
4721 IList<ParameterDefinition> parameters = method.Parameters;
4723 genDeclType = method.DeclaringType;
4724 genDeclMethod = method;
4725 AppendParameters (buf, method.DeclaringType.GenericParameters, parameters);
4729 genDeclMethod = null;
4731 return buf.ToString ();
4734 private StringBuilder AppendParameters (StringBuilder buf, IList<GenericParameter> genArgs, IList<ParameterDefinition> parameters)
4736 if (parameters.Count == 0)
4741 AppendParameter (buf, genArgs, parameters [0]);
4742 for (int i = 1; i < parameters.Count; ++i) {
4744 AppendParameter (buf, genArgs, parameters [i]);
4747 return buf.Append (')');
4750 private StringBuilder AppendParameter (StringBuilder buf, IList<GenericParameter> genArgs, ParameterDefinition parameter)
4752 AddTypeCount = false;
4753 buf.Append (GetTypeName (parameter.ParameterType));
4754 AddTypeCount = true;
4758 protected override string GetPropertyName (PropertyReference property)
4762 PropertyDefinition propertyDef = property as PropertyDefinition;
4763 MethodDefinition method = null;
4764 if (propertyDef != null)
4765 method = propertyDef.GetMethod ?? propertyDef.SetMethod;
4766 if (method != null && !DocUtils.IsExplicitlyImplemented (method))
4767 name = property.Name;
4769 TypeReference iface;
4770 MethodReference ifaceMethod;
4771 DocUtils.GetInfoForExplicitlyImplementedMethod (method, out iface, out ifaceMethod);
4772 AddTypeCount = false;
4773 name = string.Join ("#", new string[]{
4774 GetTypeName (iface).Replace (".", "#"),
4775 DocUtils.GetMember (property.Name)
4777 AddTypeCount = true;
4780 StringBuilder buf = new StringBuilder ();
4781 buf.Append (GetName (property.DeclaringType));
4784 IList<ParameterDefinition> parameters = property.Parameters;
4785 if (parameters.Count > 0) {
4786 genDeclType = property.DeclaringType;
4788 IList<GenericParameter> genArgs = property.DeclaringType.GenericParameters;
4789 AppendParameter (buf, genArgs, parameters [0]);
4790 for (int i = 1; i < parameters.Count; ++i) {
4792 AppendParameter (buf, genArgs, parameters [i]);
4797 return buf.ToString ();
4800 protected override string GetFieldName (FieldReference field)
4802 return string.Format ("{0}.{1}",
4803 GetName (field.DeclaringType), field.Name);
4806 protected override string GetEventName (EventReference e)
4808 return string.Format ("{0}.{1}",
4809 GetName (e.DeclaringType), e.Name);
4812 protected override string GetTypeDeclaration (TypeDefinition type)
4814 string name = GetName (type);
4820 protected override string GetConstructorDeclaration (MethodDefinition constructor)
4822 string name = GetName (constructor);
4828 protected override string GetMethodDeclaration (MethodDefinition method)
4830 string name = GetName (method);
4833 if (method.Name == "op_Implicit" || method.Name == "op_Explicit") {
4834 genDeclType = method.DeclaringType;
4835 genDeclMethod = method;
4836 name += "~" + GetName (method.ReturnType);
4838 genDeclMethod = null;
4843 protected override string GetPropertyDeclaration (PropertyDefinition property)
4845 string name = GetName (property);
4851 protected override string GetFieldDeclaration (FieldDefinition field)
4853 string name = GetName (field);
4859 protected override string GetEventDeclaration (EventDefinition e)
4861 string name = GetName (e);
4868 class FileNameMemberFormatter : SlashDocMemberFormatter {
4869 protected override StringBuilder AppendNamespace (StringBuilder buf, TypeReference type)
4874 protected override char NestedTypeSeparator {