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 = AssemblyFactory.GetAssembly (name);
218 } catch (System.IO.FileNotFoundException) { }
220 if (assembly == null)
221 throw new InvalidOperationException("Assembly " + name + " not found.");
223 assembly.Resolver = assemblyResolver;
227 private static void WriteXml(XmlElement element, System.IO.TextWriter output) {
228 OrderTypeAttributes (element);
229 XmlTextWriter writer = new XmlTextWriter(output);
230 writer.Formatting = Formatting.Indented;
231 writer.Indentation = 2;
232 writer.IndentChar = ' ';
233 element.WriteTo(writer);
237 private static void WriteFile (string filename, FileMode mode, Action<TextWriter> action)
239 Action<string> creator = file => {
240 using (var writer = OpenWrite (file, mode))
244 MdocFile.UpdateFile (filename, creator);
247 private static void OrderTypeAttributes (XmlElement e)
249 foreach (XmlElement type in e.SelectNodes ("//Type")) {
250 OrderTypeAttributes (type.Attributes);
254 static readonly string[] TypeAttributeOrder = {
255 "Name", "FullName", "FullNameSP", "Maintainer"
258 private static void OrderTypeAttributes (XmlAttributeCollection c)
260 XmlAttribute[] attrs = new XmlAttribute [TypeAttributeOrder.Length];
261 for (int i = 0; i < c.Count; ++i) {
262 XmlAttribute a = c [i];
263 for (int j = 0; j < TypeAttributeOrder.Length; ++j) {
264 if (a.Name == TypeAttributeOrder [j]) {
270 for (int i = attrs.Length-1; i >= 0; --i) {
271 XmlAttribute n = attrs [i];
274 XmlAttribute r = null;
275 for (int j = i+1; j < attrs.Length; ++j) {
276 if (attrs [j] != null) {
284 c.InsertBefore (n, r);
288 private XmlDocument CreateIndexStub()
290 XmlDocument index = new XmlDocument();
292 XmlElement index_root = index.CreateElement("Overview");
293 index.AppendChild(index_root);
295 if (assemblies.Count == 0)
296 throw new Exception ("No assembly");
298 XmlElement index_assemblies = index.CreateElement("Assemblies");
299 index_root.AppendChild(index_assemblies);
301 XmlElement index_remarks = index.CreateElement("Remarks");
302 index_remarks.InnerText = "To be added.";
303 index_root.AppendChild(index_remarks);
305 XmlElement index_copyright = index.CreateElement("Copyright");
306 index_copyright.InnerText = "To be added.";
307 index_root.AppendChild(index_copyright);
309 XmlElement index_types = index.CreateElement("Types");
310 index_root.AppendChild(index_types);
315 private static void WriteNamespaceStub(string ns, string outdir) {
316 XmlDocument index = new XmlDocument();
318 XmlElement index_root = index.CreateElement("Namespace");
319 index.AppendChild(index_root);
321 index_root.SetAttribute("Name", ns);
323 XmlElement index_docs = index.CreateElement("Docs");
324 index_root.AppendChild(index_docs);
326 XmlElement index_summary = index.CreateElement("summary");
327 index_summary.InnerText = "To be added.";
328 index_docs.AppendChild(index_summary);
330 XmlElement index_remarks = index.CreateElement("remarks");
331 index_remarks.InnerText = "To be added.";
332 index_docs.AppendChild(index_remarks);
334 WriteFile (outdir + "/ns-" + ns + ".xml", FileMode.CreateNew,
335 writer => WriteXml (index.DocumentElement, writer));
338 public void DoUpdateTypes (string basepath, List<string> typenames, string dest)
340 var index = CreateIndexForTypes (dest);
342 var found = new HashSet<string> ();
343 foreach (AssemblyDefinition assembly in assemblies) {
344 foreach (TypeDefinition type in docEnum.GetDocumentationTypes (assembly, typenames)) {
345 string relpath = DoUpdateType (type, basepath, dest);
349 found.Add (type.FullName);
354 index.Add (assembly);
362 if (ignore_missing_types)
365 var notFound = from n in typenames where !found.Contains (n) select n;
367 throw new InvalidOperationException("Type(s) not found: " + string.Join (", ", notFound.ToArray ()));
370 class IndexForTypes {
376 XmlElement index_types;
377 XmlElement index_assemblies;
379 public IndexForTypes (MDocUpdater app, string indexFile, XmlDocument index)
382 this.indexFile = indexFile;
385 index_types = WriteElement (index.DocumentElement, "Types");
386 index_assemblies = WriteElement (index.DocumentElement, "Assemblies");
389 public void Add (AssemblyDefinition assembly)
391 if (index_assemblies.SelectSingleNode ("Assembly[@Name='" + assembly.Name.Name + "']") != null)
394 app.AddIndexAssembly (assembly, index_assemblies);
397 public void Add (TypeDefinition type)
399 app.AddIndexType (type, index_types);
404 SortIndexEntries (index_types);
405 WriteFile (indexFile, FileMode.Create,
406 writer => WriteXml (index.DocumentElement, writer));
410 IndexForTypes CreateIndexForTypes (string dest)
412 string indexFile = Path.Combine (dest, "index.xml");
413 if (File.Exists (indexFile))
415 return new IndexForTypes (this, indexFile, CreateIndexStub ());
418 public string DoUpdateType (TypeDefinition type, string basepath, string dest)
420 if (type.Namespace == null)
421 Warning ("warning: The type `{0}' is in the root namespace. This may cause problems with display within monodoc.",
423 if (!IsPublic (type))
426 // Must get the A+B form of the type name.
427 string typename = GetTypeFileName(type);
429 string reltypefile = DocUtils.PathCombine (DocUtils.GetNamespace (type), typename + ".xml");
430 string typefile = Path.Combine (basepath, reltypefile);
431 System.IO.FileInfo file = new System.IO.FileInfo(typefile);
433 string output = null;
436 } else if (dest == "-") {
439 output = Path.Combine (dest, reltypefile);
444 XmlDocument basefile = new XmlDocument();
446 basefile.Load(typefile);
447 } catch (Exception e) {
448 throw new InvalidOperationException("Error loading " + typefile + ": " + e.Message, e);
451 DoUpdateType2("Updating", basefile, type, output, false);
454 XmlElement td = StubType(type, output);
458 System.IO.DirectoryInfo dir = new System.IO.DirectoryInfo (DocUtils.PathCombine (dest, type.Namespace));
461 Console.WriteLine("Namespace Directory Created: " + type.Namespace);
467 public void DoUpdateNS (string ns, string nspath, string outpath)
469 Dictionary<TypeDefinition, object> seenTypes = new Dictionary<TypeDefinition,object> ();
470 AssemblyDefinition assembly = assemblies [0];
472 foreach (System.IO.FileInfo file in new System.IO.DirectoryInfo(nspath).GetFiles("*.xml")) {
473 XmlDocument basefile = new XmlDocument();
474 string typefile = Path.Combine(nspath, file.Name);
476 basefile.Load(typefile);
477 } catch (Exception e) {
478 throw new InvalidOperationException("Error loading " + typefile + ": " + e.Message, e);
482 GetTypeFileName (basefile.SelectSingleNode("Type/@FullName").InnerText);
483 TypeDefinition type = assembly.GetType(typename);
485 Warning ("Type no longer in assembly: " + typename);
489 seenTypes[type] = seenTypes;
490 DoUpdateType2("Updating", basefile, type, Path.Combine(outpath, file.Name), false);
493 // Stub types not in the directory
494 foreach (TypeDefinition type in docEnum.GetDocumentationTypes (assembly, null)) {
495 if (type.Namespace != ns || seenTypes.ContainsKey(type))
498 XmlElement td = StubType(type, Path.Combine(outpath, GetTypeFileName(type) + ".xml"));
499 if (td == null) continue;
503 private static string GetTypeFileName (TypeReference type)
505 return filenameFormatter.GetName (type);
508 public static string GetTypeFileName (string typename)
510 StringBuilder filename = new StringBuilder (typename.Length);
514 for (int i = 0; i < typename.Length; ++i) {
515 char c = typename [i];
524 filename.Append ('`').Append ((numArgs+1).ToString());
539 return filename.ToString ();
542 private void AddIndexAssembly (AssemblyDefinition assembly, XmlElement parent)
544 XmlElement index_assembly = parent.OwnerDocument.CreateElement("Assembly");
545 index_assembly.SetAttribute ("Name", assembly.Name.Name);
546 index_assembly.SetAttribute ("Version", assembly.Name.Version.ToString());
548 AssemblyNameDefinition name = assembly.Name;
549 if (name.HasPublicKey) {
550 XmlElement pubkey = parent.OwnerDocument.CreateElement ("AssemblyPublicKey");
551 var key = new StringBuilder (name.PublicKey.Length*3 + 2);
553 foreach (byte b in name.PublicKey)
554 key.AppendFormat ("{0,2:x2} ", b);
556 pubkey.InnerText = key.ToString ();
557 index_assembly.AppendChild (pubkey);
560 if (!string.IsNullOrEmpty (name.Culture)) {
561 XmlElement culture = parent.OwnerDocument.CreateElement ("AssemblyCulture");
562 culture.InnerText = name.Culture;
563 index_assembly.AppendChild (culture);
566 MakeAttributes (index_assembly, GetCustomAttributes (assembly.CustomAttributes, ""));
567 parent.AppendChild(index_assembly);
570 private void AddIndexType (TypeDefinition type, XmlElement index_types)
572 string typename = GetTypeFileName(type);
574 // Add namespace and type nodes into the index file as needed
575 string ns = DocUtils.GetNamespace (type);
576 XmlElement nsnode = (XmlElement) index_types.SelectSingleNode ("Namespace[@Name='" + ns + "']");
577 if (nsnode == null) {
578 nsnode = index_types.OwnerDocument.CreateElement("Namespace");
579 nsnode.SetAttribute ("Name", ns);
580 index_types.AppendChild (nsnode);
582 string doc_typename = GetDocTypeName (type);
583 XmlElement typenode = (XmlElement) nsnode.SelectSingleNode ("Type[@Name='" + typename + "']");
584 if (typenode == null) {
585 typenode = index_types.OwnerDocument.CreateElement ("Type");
586 typenode.SetAttribute ("Name", typename);
587 nsnode.AppendChild (typenode);
589 if (typename != doc_typename)
590 typenode.SetAttribute("DisplayName", doc_typename);
592 typenode.RemoveAttribute("DisplayName");
594 typenode.SetAttribute ("Kind", GetTypeKind (type));
597 private void DoUpdateAssemblies (string source, string dest)
599 string indexfile = dest + "/index.xml";
601 if (System.IO.File.Exists(indexfile)) {
602 index = new XmlDocument();
603 index.Load(indexfile);
606 ClearElement(index.DocumentElement, "Assembly");
607 ClearElement(index.DocumentElement, "Attributes");
609 index = CreateIndexStub();
612 string defaultTitle = "Untitled";
613 if (assemblies.Count == 1)
614 defaultTitle = assemblies[0].Name.Name;
615 WriteElementInitialText(index.DocumentElement, "Title", defaultTitle);
617 XmlElement index_types = WriteElement(index.DocumentElement, "Types");
618 XmlElement index_assemblies = WriteElement(index.DocumentElement, "Assemblies");
619 index_assemblies.RemoveAll ();
622 HashSet<string> goodfiles = new HashSet<string> ();
624 foreach (AssemblyDefinition assm in assemblies) {
625 AddIndexAssembly (assm, index_assemblies);
626 DoUpdateAssembly (assm, index_types, source, dest, goodfiles);
629 SortIndexEntries (index_types);
631 CleanupFiles (dest, goodfiles);
632 CleanupIndexTypes (index_types, goodfiles);
633 CleanupExtensions (index_types);
635 WriteFile (indexfile, FileMode.Create,
636 writer => WriteXml(index.DocumentElement, writer));
639 private static char[] InvalidFilenameChars = {'\\', '/', ':', '*', '?', '"', '<', '>', '|'};
641 private void DoUpdateAssembly (AssemblyDefinition assembly, XmlElement index_types, string source, string dest, HashSet<string> goodfiles)
643 foreach (TypeDefinition type in docEnum.GetDocumentationTypes (assembly, null)) {
644 string typename = GetTypeFileName(type);
645 if (!IsPublic (type) || typename.IndexOfAny (InvalidFilenameChars) >= 0)
648 string reltypepath = DoUpdateType (type, source, dest);
649 if (reltypepath == null)
652 // Add namespace and type nodes into the index file as needed
653 AddIndexType (type, index_types);
655 // Ensure the namespace index file exists
656 string onsdoc = DocUtils.PathCombine (dest, type.Namespace + ".xml");
657 string nsdoc = DocUtils.PathCombine (dest, "ns-" + type.Namespace + ".xml");
658 if (File.Exists (onsdoc)) {
659 File.Move (onsdoc, nsdoc);
662 if (!File.Exists (nsdoc)) {
663 Console.WriteLine("New Namespace File: " + type.Namespace);
664 WriteNamespaceStub(type.Namespace, dest);
667 goodfiles.Add (reltypepath);
671 private static void SortIndexEntries (XmlElement indexTypes)
673 XmlNodeList namespaces = indexTypes.SelectNodes ("Namespace");
674 XmlNodeComparer c = new AttributeNameComparer ();
675 SortXmlNodes (indexTypes, namespaces, c);
677 for (int i = 0; i < namespaces.Count; ++i)
678 SortXmlNodes (namespaces [i], namespaces [i].SelectNodes ("Type"), c);
681 private static void SortXmlNodes (XmlNode parent, XmlNodeList children, XmlNodeComparer comparer)
683 MyXmlNodeList l = new MyXmlNodeList (children.Count);
684 for (int i = 0; i < children.Count; ++i)
685 l.Add (children [i]);
687 for (int i = l.Count - 1; i > 0; --i) {
688 parent.InsertBefore (parent.RemoveChild ((XmlNode) l [i-1]), (XmlNode) l [i]);
692 abstract class XmlNodeComparer : IComparer, IComparer<XmlNode>
694 public abstract int Compare (XmlNode x, XmlNode y);
696 public int Compare (object x, object y)
698 return Compare ((XmlNode) x, (XmlNode) y);
702 class AttributeNameComparer : XmlNodeComparer {
705 public AttributeNameComparer ()
710 public AttributeNameComparer (string attribute)
712 this.attribute = attribute;
715 public override int Compare (XmlNode x, XmlNode y)
717 return x.Attributes [attribute].Value.CompareTo (y.Attributes [attribute].Value);
721 class VersionComparer : XmlNodeComparer {
722 public override int Compare (XmlNode x, XmlNode y)
724 // Some of the existing docs use e.g. 1.0.x.x, which Version doesn't like.
725 string a = GetVersion (x.InnerText);
726 string b = GetVersion (y.InnerText);
727 return new Version (a).CompareTo (new Version (b));
730 static string GetVersion (string v)
732 int n = v.IndexOf ("x");
735 return v.Substring (0, n-1);
739 private static string GetTypeKind (TypeDefinition type)
742 return "Enumeration";
743 if (type.IsValueType)
745 if (type.IsInterface)
747 if (DocUtils.IsDelegate (type))
749 if (type.IsClass || type.FullName == "System.Enum") // FIXME
751 throw new ArgumentException ("Unknown kind for type: " + type.FullName);
754 private static bool IsPublic (TypeDefinition type)
756 TypeDefinition decl = type;
757 while (decl != null) {
758 if (!(decl.IsPublic || decl.IsNestedPublic)) {
761 decl = (TypeDefinition) decl.DeclaringType;
766 private void CleanupFiles (string dest, HashSet<string> goodfiles)
768 // Look for files that no longer correspond to types
769 foreach (System.IO.DirectoryInfo nsdir in new System.IO.DirectoryInfo(dest).GetDirectories("*")) {
770 foreach (System.IO.FileInfo typefile in nsdir.GetFiles("*.xml")) {
771 string relTypeFile = Path.Combine(nsdir.Name, typefile.Name);
772 if (!goodfiles.Contains (relTypeFile)) {
773 XmlDocument doc = new XmlDocument ();
774 doc.Load (typefile.FullName);
775 XmlElement e = doc.SelectSingleNode("/Type") as XmlElement;
776 if (UpdateAssemblyVersions(e, GetAssemblyVersions(), false)) {
777 using (TextWriter writer = OpenWrite (typefile.FullName, FileMode.Truncate))
778 WriteXml(doc.DocumentElement, writer);
779 goodfiles.Add (relTypeFile);
782 string newname = typefile.FullName + ".remove";
783 try { System.IO.File.Delete(newname); } catch (Exception) { }
784 try { typefile.MoveTo(newname); } catch (Exception) { }
785 Console.WriteLine("Class no longer present; file renamed: " + Path.Combine(nsdir.Name, typefile.Name));
791 private static TextWriter OpenWrite (string path, FileMode mode)
793 var w = new StreamWriter (
794 new FileStream (path, mode),
795 new UTF8Encoding (false)
801 private string[] GetAssemblyVersions ()
803 return (from a in assemblies select GetAssemblyVersion (a)).ToArray ();
806 private static void CleanupIndexTypes (XmlElement index_types, HashSet<string> goodfiles)
808 // Look for type nodes that no longer correspond to types
809 MyXmlNodeList remove = new MyXmlNodeList ();
810 foreach (XmlElement typenode in index_types.SelectNodes("Namespace/Type")) {
811 string fulltypename = Path.Combine (((XmlElement)typenode.ParentNode).GetAttribute("Name"), typenode.GetAttribute("Name") + ".xml");
812 if (!goodfiles.Contains (fulltypename)) {
813 remove.Add (typenode);
816 foreach (XmlNode n in remove)
817 n.ParentNode.RemoveChild (n);
820 private void CleanupExtensions (XmlElement index_types)
822 XmlNode e = index_types.SelectSingleNode ("/Overview/ExtensionMethods");
823 if (extensionMethods.Count == 0) {
826 index_types.SelectSingleNode ("/Overview").RemoveChild (e);
830 e = index_types.OwnerDocument.CreateElement ("ExtensionMethods");
831 index_types.SelectSingleNode ("/Overview").AppendChild (e);
835 extensionMethods.Sort (DefaultExtensionMethodComparer);
836 foreach (XmlNode m in extensionMethods) {
837 e.AppendChild (index_types.OwnerDocument.ImportNode (m, true));
841 class ExtensionMethodComparer : XmlNodeComparer {
842 public override int Compare (XmlNode x, XmlNode y)
844 XmlNode xLink = x.SelectSingleNode ("Member/Link");
845 XmlNode yLink = y.SelectSingleNode ("Member/Link");
847 int n = xLink.Attributes ["Type"].Value.CompareTo (
848 yLink.Attributes ["Type"].Value);
851 n = xLink.Attributes ["Member"].Value.CompareTo (
852 yLink.Attributes ["Member"].Value);
853 if (n == 0 && !object.ReferenceEquals (x, y))
854 throw new InvalidOperationException ("Duplicate extension method found!");
859 static readonly XmlNodeComparer DefaultExtensionMethodComparer = new ExtensionMethodComparer ();
861 public void DoUpdateType2 (string message, XmlDocument basefile, TypeDefinition type, string output, bool insertSince)
863 Console.WriteLine(message + ": " + type.FullName);
865 StringToXmlNodeMap seenmembers = new StringToXmlNodeMap ();
867 // Update type metadata
868 UpdateType(basefile.DocumentElement, type);
870 // Update existing members. Delete member nodes that no longer should be there,
871 // and remember what members are already documented so we don't add them again.
873 MyXmlNodeList todelete = new MyXmlNodeList ();
874 foreach (DocsNodeInfo info in docEnum.GetDocumentationMembers (basefile, type)) {
875 XmlElement oldmember = info.Node;
876 IMemberReference oldmember2 = info.Member;
877 string sig = oldmember2 != null ? memberFormatters [0].GetDeclaration (oldmember2) : null;
879 // Interface implementations and overrides are deleted from the docs
880 // unless the overrides option is given.
881 if (oldmember2 != null && sig == null)
884 // Deleted (or signature changed)
885 if (oldmember2 == null) {
886 if (UpdateAssemblyVersions (oldmember, new string[]{ GetAssemblyVersion (type.Module.Assembly) }, false))
888 DeleteMember ("Member Removed", output, oldmember, todelete);
893 if (seenmembers.ContainsKey (sig)) {
894 if (object.ReferenceEquals (oldmember, seenmembers [sig])) {
895 // ignore, already seen
897 else if (DefaultMemberComparer.Compare (oldmember, seenmembers [sig]) == 0)
898 DeleteMember ("Duplicate Member Found", output, oldmember, todelete);
900 Warning ("TODO: found a duplicate member '{0}', but it's not identical to the prior member found!", sig);
904 // Update signature information
907 seenmembers.Add (sig, oldmember);
909 foreach (XmlElement oldmember in todelete)
910 oldmember.ParentNode.RemoveChild (oldmember);
913 if (!DocUtils.IsDelegate (type)) {
914 XmlNode members = WriteElement (basefile.DocumentElement, "Members");
915 foreach (IMemberReference m in type.GetMembers()) {
916 if (m is TypeDefinition) continue;
918 string sig = memberFormatters [0].GetDeclaration (m);
919 if (sig == null) continue;
920 if (seenmembers.ContainsKey(sig)) continue;
922 XmlElement mm = MakeMember(basefile, new DocsNodeInfo (null, m));
923 if (mm == null) continue;
924 members.AppendChild( mm );
926 Console.WriteLine("Member Added: " + mm.SelectSingleNode("MemberSignature/@Value").InnerText);
931 // Import code snippets from files
932 foreach (XmlNode code in basefile.GetElementsByTagName("code")) {
933 if (!(code is XmlElement)) continue;
934 string file = ((XmlElement)code).GetAttribute("src");
935 string lang = ((XmlElement)code).GetAttribute("lang");
937 string src = GetCodeSource (lang, Path.Combine (srcPath, file));
939 code.InnerText = src;
943 if (insertSince && since != null) {
944 XmlNode docs = basefile.DocumentElement.SelectSingleNode("Docs");
945 docs.AppendChild (CreateSinceNode (basefile));
949 XmlElement d = basefile.DocumentElement ["Docs"];
950 XmlElement m = basefile.DocumentElement ["Members"];
951 if (d != null && m != null)
952 basefile.DocumentElement.InsertBefore (
953 basefile.DocumentElement.RemoveChild (d), m);
958 WriteXml(basefile.DocumentElement, Console.Out);
960 FileInfo file = new FileInfo (output);
961 if (!file.Directory.Exists) {
962 Console.WriteLine("Namespace Directory Created: " + type.Namespace);
963 file.Directory.Create ();
965 WriteFile (output, FileMode.Create,
966 writer => WriteXml(basefile.DocumentElement, writer));
970 private string GetCodeSource (string lang, string file)
973 if (lang == "C#" && (anchorStart = file.IndexOf (".cs#")) >= 0) {
974 // Grab the specified region
975 string region = "#region " + file.Substring (anchorStart + 4);
976 file = file.Substring (0, anchorStart + 3);
978 using (StreamReader reader = new StreamReader (file)) {
980 StringBuilder src = new StringBuilder ();
982 while ((line = reader.ReadLine ()) != null) {
983 if (line.Trim() == region) {
984 indent = line.IndexOf (region);
987 if (indent >= 0 && line.Trim().StartsWith ("#endregion")) {
992 (line.Length > 0 ? line.Substring (indent) : string.Empty) +
995 return src.ToString ();
997 } catch (Exception e) {
998 Warning ("Could not load <code/> file '{0}' region '{1}': {2}",
999 file, region, show_exceptions ? e.ToString () : e.Message);
1004 using (StreamReader reader = new StreamReader (file))
1005 return reader.ReadToEnd ();
1006 } catch (Exception e) {
1007 Warning ("Could not load <code/> file '" + file + "': " + e.Message);
1012 void DeleteMember (string reason, string output, XmlNode member, MyXmlNodeList todelete)
1014 string format = output != null
1015 ? "{0}: File='{1}'; Signature='{4}'"
1016 : "{0}: XPath='/Type[@FullName=\"{2}\"]/Members/Member[@MemberName=\"{3}\"]'; Signature='{4}'";
1020 member.OwnerDocument.DocumentElement.GetAttribute ("FullName"),
1021 member.Attributes ["MemberName"].Value,
1022 member.SelectSingleNode ("MemberSignature[@Language='C#']/@Value").Value);
1023 if (!delete && MemberDocsHaveUserContent (member)) {
1024 Warning ("Member deletions must be enabled with the --delete option.");
1026 todelete.Add (member);
1031 class MemberComparer : XmlNodeComparer {
1032 public override int Compare (XmlNode x, XmlNode y)
1035 string xMemberName = x.Attributes ["MemberName"].Value;
1036 string yMemberName = y.Attributes ["MemberName"].Value;
1038 // generic methods *end* with '>'
1039 // it's possible for explicitly implemented generic interfaces to
1040 // contain <...> without being a generic method
1041 if ((!xMemberName.EndsWith (">") || !yMemberName.EndsWith (">")) &&
1042 (r = xMemberName.CompareTo (yMemberName)) != 0)
1046 if ((lt = xMemberName.IndexOf ("<")) >= 0)
1047 xMemberName = xMemberName.Substring (0, lt);
1048 if ((lt = yMemberName.IndexOf ("<")) >= 0)
1049 yMemberName = yMemberName.Substring (0, lt);
1050 if ((r = xMemberName.CompareTo (yMemberName)) != 0)
1053 // if @MemberName matches, then it's either two different types of
1054 // members sharing the same name, e.g. field & property, or it's an
1055 // overloaded method.
1056 // for different type, sort based on MemberType value.
1057 r = x.SelectSingleNode ("MemberType").InnerText.CompareTo (
1058 y.SelectSingleNode ("MemberType").InnerText);
1062 // same type -- must be an overloaded method. Sort based on type
1063 // parameter count, then parameter count, then by the parameter
1065 XmlNodeList xTypeParams = x.SelectNodes ("TypeParameters/TypeParameter");
1066 XmlNodeList yTypeParams = y.SelectNodes ("TypeParameters/TypeParameter");
1067 if (xTypeParams.Count != yTypeParams.Count)
1068 return xTypeParams.Count <= yTypeParams.Count ? -1 : 1;
1069 for (int i = 0; i < xTypeParams.Count; ++i) {
1070 r = xTypeParams [i].Attributes ["Name"].Value.CompareTo (
1071 yTypeParams [i].Attributes ["Name"].Value);
1076 XmlNodeList xParams = x.SelectNodes ("Parameters/Parameter");
1077 XmlNodeList yParams = y.SelectNodes ("Parameters/Parameter");
1078 if (xParams.Count != yParams.Count)
1079 return xParams.Count <= yParams.Count ? -1 : 1;
1080 for (int i = 0; i < xParams.Count; ++i) {
1081 r = xParams [i].Attributes ["Type"].Value.CompareTo (
1082 yParams [i].Attributes ["Type"].Value);
1086 // all parameters match, but return value might not match if it was
1087 // changed between one version and another.
1088 XmlNode xReturn = x.SelectSingleNode ("ReturnValue/ReturnType");
1089 XmlNode yReturn = y.SelectSingleNode ("ReturnValue/ReturnType");
1090 if (xReturn != null && yReturn != null) {
1091 r = xReturn.InnerText.CompareTo (yReturn.InnerText);
1100 static readonly MemberComparer DefaultMemberComparer = new MemberComparer ();
1102 private static void SortTypeMembers (XmlNode members)
1104 if (members == null)
1106 SortXmlNodes (members, members.SelectNodes ("Member"), DefaultMemberComparer);
1109 private static bool MemberDocsHaveUserContent (XmlNode e)
1111 e = (XmlElement)e.SelectSingleNode("Docs");
1112 if (e == null) return false;
1113 foreach (XmlElement d in e.SelectNodes("*"))
1114 if (d.InnerText != "" && !d.InnerText.StartsWith("To be added"))
1119 // UPDATE HELPER FUNCTIONS
1121 // CREATE A STUB DOCUMENTATION FILE
1123 public XmlElement StubType (TypeDefinition type, string output)
1125 string typesig = typeFormatters [0].GetDeclaration (type);
1126 if (typesig == null) return null; // not publicly visible
1128 XmlDocument doc = new XmlDocument();
1129 XmlElement root = doc.CreateElement("Type");
1130 doc.AppendChild (root);
1132 DoUpdateType2 ("New Type", doc, type, output, true);
1137 private XmlElement CreateSinceNode (XmlDocument doc)
1139 XmlElement s = doc.CreateElement ("since");
1140 s.SetAttribute ("version", since);
1144 // STUBBING/UPDATING FUNCTIONS
1146 public void UpdateType (XmlElement root, TypeDefinition type)
1148 root.SetAttribute("Name", GetDocTypeName (type));
1149 root.SetAttribute("FullName", GetDocTypeFullName (type));
1151 foreach (MemberFormatter f in typeFormatters) {
1152 string element = "TypeSignature[@Language='" + f.Language + "']";
1153 WriteElementAttribute (root, element, "Language", f.Language);
1154 WriteElementAttribute (root, element, "Value", f.GetDeclaration (type));
1157 XmlElement ass = WriteElement(root, "AssemblyInfo");
1158 WriteElementText(ass, "AssemblyName", type.Module.Assembly.Name.Name);
1159 if (!no_assembly_versions) {
1160 UpdateAssemblyVersions (root, type, true);
1163 var versions = ass.SelectNodes ("AssemblyVersion").Cast<XmlNode> ().ToList ();
1164 foreach (var version in versions)
1165 ass.RemoveChild (version);
1167 if (!string.IsNullOrEmpty (type.Module.Assembly.Name.Culture))
1168 WriteElementText(ass, "AssemblyCulture", type.Module.Assembly.Name.Culture);
1170 ClearElement(ass, "AssemblyCulture");
1172 // Why-oh-why do we put assembly attributes in each type file?
1173 // Neither monodoc nor monodocs2html use them, so I'm deleting them
1174 // since they're outdated in current docs, and a waste of space.
1175 //MakeAttributes(ass, type.Assembly, true);
1176 XmlNode assattrs = ass.SelectSingleNode("Attributes");
1177 if (assattrs != null)
1178 ass.RemoveChild(assattrs);
1180 NormalizeWhitespace(ass);
1182 if (type.IsGenericType ()) {
1183 MakeTypeParameters (root, type.GenericParameters);
1185 ClearElement(root, "TypeParameters");
1188 if (type.BaseType != null) {
1189 XmlElement basenode = WriteElement(root, "Base");
1191 string basetypename = GetDocTypeFullName (type.BaseType);
1192 if (basetypename == "System.MulticastDelegate") basetypename = "System.Delegate";
1193 WriteElementText(root, "Base/BaseTypeName", basetypename);
1195 // Document how this type instantiates the generic parameters of its base type
1196 TypeReference origBase = type.BaseType.GetOriginalType ();
1197 if (origBase.IsGenericType ()) {
1198 ClearElement(basenode, "BaseTypeArguments");
1199 GenericInstanceType baseInst = type.BaseType as GenericInstanceType;
1200 GenericArgumentCollection baseGenArgs = baseInst == null ? null : baseInst.GenericArguments;
1201 GenericParameterCollection baseGenParams = origBase.GenericParameters;
1202 if (baseGenArgs.Count != baseGenParams.Count)
1203 throw new InvalidOperationException ("internal error: number of generic arguments doesn't match number of generic parameters.");
1204 for (int i = 0; baseGenArgs != null && i < baseGenArgs.Count; i++) {
1205 GenericParameter param = baseGenParams [i];
1206 TypeReference value = baseGenArgs [i];
1208 XmlElement bta = WriteElement(basenode, "BaseTypeArguments");
1209 XmlElement arg = bta.OwnerDocument.CreateElement("BaseTypeArgument");
1210 bta.AppendChild(arg);
1211 arg.SetAttribute ("TypeParamName", param.Name);
1212 arg.InnerText = GetDocTypeFullName (value);
1216 ClearElement(root, "Base");
1219 if (!DocUtils.IsDelegate (type) && !type.IsEnum) {
1220 IEnumerable<TypeReference> userInterfaces = DocUtils.GetUserImplementedInterfaces (type);
1221 List<string> interface_names = userInterfaces
1222 .Select (iface => GetDocTypeFullName (iface))
1226 XmlElement interfaces = WriteElement(root, "Interfaces");
1227 interfaces.RemoveAll();
1228 foreach (string iname in interface_names) {
1229 XmlElement iface = root.OwnerDocument.CreateElement("Interface");
1230 interfaces.AppendChild(iface);
1231 WriteElementText(iface, "InterfaceName", iname);
1234 ClearElement(root, "Interfaces");
1237 MakeAttributes (root, GetCustomAttributes (type));
1239 if (DocUtils.IsDelegate (type)) {
1240 MakeTypeParameters (root, type.GenericParameters);
1241 MakeParameters(root, type.GetMethod("Invoke").Parameters);
1242 MakeReturnValue(root, type.GetMethod("Invoke"));
1245 DocsNodeInfo typeInfo = new DocsNodeInfo (WriteElement(root, "Docs"), type);
1246 MakeDocNode (typeInfo);
1248 if (!DocUtils.IsDelegate (type))
1249 WriteElement (root, "Members");
1251 NormalizeWhitespace(root);
1254 internal static IEnumerable<T> Sort<T> (IEnumerable<T> list)
1256 List<T> l = new List<T> (list);
1261 private void UpdateMember (DocsNodeInfo info)
1263 XmlElement me = (XmlElement) info.Node;
1264 IMemberReference mi = info.Member;
1266 foreach (MemberFormatter f in memberFormatters) {
1267 string element = "MemberSignature[@Language='" + f.Language + "']";
1268 WriteElementAttribute (me, element, "Language", f.Language);
1269 WriteElementAttribute (me, element, "Value", f.GetDeclaration (mi));
1272 WriteElementText(me, "MemberType", GetMemberType(mi));
1274 if (!no_assembly_versions) {
1275 UpdateAssemblyVersions (me, mi, true);
1278 ClearElement (me, "AssemblyInfo");
1281 MakeAttributes (me, GetCustomAttributes (mi));
1283 MakeReturnValue(me, mi);
1284 if (mi is MethodReference) {
1285 MethodReference mb = (MethodReference) mi;
1286 if (mb.IsGenericMethod ())
1287 MakeTypeParameters (me, mb.GenericParameters);
1289 MakeParameters(me, mi);
1292 if (mi is FieldDefinition && GetFieldConstValue ((FieldDefinition)mi, out fieldValue))
1293 WriteElementText(me, "MemberValue", fieldValue);
1295 info.Node = WriteElement (me, "Docs");
1297 UpdateExtensionMethods (me, info);
1300 IEnumerable<string> GetCustomAttributes (IMemberReference mi)
1302 IEnumerable<string> attrs = Enumerable.Empty<string>();
1304 ICustomAttributeProvider p = mi as ICustomAttributeProvider;
1306 attrs = attrs.Concat (GetCustomAttributes (p.CustomAttributes, ""));
1308 PropertyReference pr = mi as PropertyReference;
1310 PropertyDefinition pd = pr.Resolve ();
1311 if (pd.GetMethod != null)
1312 attrs = attrs.Concat (GetCustomAttributes (pd.GetMethod.CustomAttributes, "get: "));
1313 if (pd.SetMethod != null)
1314 attrs = attrs.Concat (GetCustomAttributes (pd.SetMethod.CustomAttributes, "set: "));
1317 EventReference er = mi as EventReference;
1319 EventDefinition ed = er.Resolve ();
1320 if (ed.AddMethod != null)
1321 attrs = attrs.Concat (GetCustomAttributes (ed.AddMethod.CustomAttributes, "add: "));
1322 if (ed.RemoveMethod != null)
1323 attrs = attrs.Concat (GetCustomAttributes (ed.RemoveMethod.CustomAttributes, "remove: "));
1329 IEnumerable<string> GetCustomAttributes (CustomAttributeCollection attributes, string prefix)
1331 foreach (CustomAttribute attribute in attributes.Cast<CustomAttribute> ()
1332 .OrderBy (ca => ca.Constructor.DeclaringType.FullName)) {
1333 if (!attribute.Resolve ()) {
1335 Warning ("warning: could not resolve type {0}.",
1336 attribute.Constructor.DeclaringType.FullName);
1338 TypeDefinition attrType = attribute.Constructor.DeclaringType as TypeDefinition;
1339 if (attrType != null && !IsPublic (attrType))
1341 if (slashdocFormatter.GetName (attribute.Constructor.DeclaringType) == null)
1344 if (Array.IndexOf (IgnorableAttributes, attribute.Constructor.DeclaringType.FullName) >= 0)
1347 StringList fields = new StringList ();
1349 ParameterDefinitionCollection parameters = attribute.Constructor.Parameters;
1350 for (int i = 0; i < attribute.ConstructorParameters.Count; ++i) {
1351 fields.Add (MakeAttributesValueString (
1352 attribute.ConstructorParameters [i],
1353 parameters [i].ParameterType));
1356 (from de in attribute.Fields.Cast<DictionaryEntry> ()
1357 select new { Type=attribute.GetFieldType (de.Key.ToString ()), Name=de.Key, Value=de.Value })
1359 (from de in attribute.Properties.Cast<DictionaryEntry> ()
1360 select new { Type=attribute.GetPropertyType (de.Key.ToString ()), Name=de.Key, Value=de.Value }))
1361 .OrderBy (v => v.Name);
1362 foreach (var d in namedArgs)
1363 fields.Add (string.Format ("{0}={1}", d.Name,
1364 MakeAttributesValueString (d.Value, d.Type)));
1366 string a2 = String.Join(", ", fields.ToArray ());
1367 if (a2 != "") a2 = "(" + a2 + ")";
1369 string name = attribute.Constructor.DeclaringType.FullName;
1370 if (name.EndsWith("Attribute")) name = name.Substring(0, name.Length-"Attribute".Length);
1371 yield return prefix + name + a2;
1375 static readonly string[] ValidExtensionMembers = {
1384 static readonly string[] ValidExtensionDocMembers = {
1390 private void UpdateExtensionMethods (XmlElement e, DocsNodeInfo info)
1392 MethodDefinition me = info.Member as MethodDefinition;
1395 if (info.Parameters.Count < 1)
1397 if (!DocUtils.IsExtensionMethod (me))
1400 XmlNode em = e.OwnerDocument.CreateElement ("ExtensionMethod");
1401 XmlNode member = e.CloneNode (true);
1402 em.AppendChild (member);
1403 RemoveExcept (member, ValidExtensionMembers);
1404 RemoveExcept (member.SelectSingleNode ("Docs"), ValidExtensionDocMembers);
1405 WriteElementText (member, "MemberType", "ExtensionMethod");
1406 XmlElement link = member.OwnerDocument.CreateElement ("Link");
1407 link.SetAttribute ("Type", slashdocFormatter.GetName (me.DeclaringType));
1408 link.SetAttribute ("Member", slashdocFormatter.GetDeclaration (me));
1409 member.AppendChild (link);
1410 AddTargets (em, info);
1412 extensionMethods.Add (em);
1415 private static void RemoveExcept (XmlNode node, string[] except)
1419 MyXmlNodeList remove = null;
1420 foreach (XmlNode n in node.ChildNodes) {
1421 if (Array.BinarySearch (except, n.Name) < 0) {
1423 remove = new MyXmlNodeList ();
1428 foreach (XmlNode n in remove)
1429 node.RemoveChild (n);
1432 private static void AddTargets (XmlNode member, DocsNodeInfo info)
1434 XmlElement targets = member.OwnerDocument.CreateElement ("Targets");
1435 member.PrependChild (targets);
1436 if (!(info.Parameters [0].ParameterType is GenericParameter)) {
1437 AppendElementAttributeText (targets, "Target", "Type",
1438 slashdocFormatter.GetDeclaration (info.Parameters [0].ParameterType));
1441 GenericParameter gp = (GenericParameter) info.Parameters [0].ParameterType;
1442 ConstraintCollection constraints = gp.Constraints;
1443 if (constraints.Count == 0)
1444 AppendElementAttributeText (targets, "Target", "Type", "System.Object");
1446 foreach (TypeReference c in constraints)
1447 AppendElementAttributeText(targets, "Target", "Type",
1448 slashdocFormatter.GetDeclaration (c));
1452 private static bool GetFieldConstValue (FieldDefinition field, out string value)
1455 TypeDefinition type = field.DeclaringType.Resolve ();
1456 if (type != null && type.IsEnum) return false;
1458 if (type != null && type.IsGenericType ()) return false;
1459 if (!field.HasConstant)
1461 if (field.IsLiteral) {
1462 object val = field.Constant;
1463 if (val == null) value = "null";
1464 else if (val is Enum) value = val.ToString();
1465 else if (val is IFormattable) {
1466 value = ((IFormattable)val).ToString();
1468 value = "\"" + value + "\"";
1470 if (value != null && value != "")
1476 // XML HELPER FUNCTIONS
1478 internal static XmlElement WriteElement(XmlNode parent, string element) {
1479 XmlElement ret = (XmlElement)parent.SelectSingleNode(element);
1481 string[] path = element.Split('/');
1482 foreach (string p in path) {
1483 ret = (XmlElement)parent.SelectSingleNode(p);
1486 if (ename.IndexOf('[') >= 0) // strip off XPath predicate
1487 ename = ename.Substring(0, ename.IndexOf('['));
1488 ret = parent.OwnerDocument.CreateElement(ename);
1489 parent.AppendChild(ret);
1498 private static void WriteElementText(XmlNode parent, string element, string value) {
1499 XmlElement node = WriteElement(parent, element);
1500 node.InnerText = value;
1503 static XmlElement AppendElementText (XmlNode parent, string element, string value)
1505 XmlElement n = parent.OwnerDocument.CreateElement (element);
1506 parent.AppendChild (n);
1507 n.InnerText = value;
1511 static XmlElement AppendElementAttributeText (XmlNode parent, string element, string attribute, string value)
1513 XmlElement n = parent.OwnerDocument.CreateElement (element);
1514 parent.AppendChild (n);
1515 n.SetAttribute (attribute, value);
1519 internal static XmlNode CopyNode (XmlNode source, XmlNode dest)
1521 XmlNode copy = dest.OwnerDocument.ImportNode (source, true);
1522 dest.AppendChild (copy);
1526 private static void WriteElementInitialText(XmlElement parent, string element, string value) {
1527 XmlElement node = (XmlElement)parent.SelectSingleNode(element);
1530 node = WriteElement(parent, element);
1531 node.InnerText = value;
1533 private static void WriteElementAttribute(XmlElement parent, string element, string attribute, string value) {
1534 XmlElement node = WriteElement(parent, element);
1535 if (node.GetAttribute(attribute) == value) return;
1536 node.SetAttribute(attribute, value);
1538 internal static void ClearElement(XmlElement parent, string name) {
1539 XmlElement node = (XmlElement)parent.SelectSingleNode(name);
1541 parent.RemoveChild(node);
1544 // DOCUMENTATION HELPER FUNCTIONS
1546 private void MakeDocNode (DocsNodeInfo info)
1548 List<GenericParameter> genericParams = info.GenericParameters;
1549 ParameterDefinitionCollection parameters = info.Parameters;
1550 TypeReference returntype = info.ReturnType;
1551 bool returnisreturn = info.ReturnIsReturn;
1552 XmlElement e = info.Node;
1553 bool addremarks = info.AddRemarks;
1555 WriteElementInitialText(e, "summary", "To be added.");
1557 if (parameters != null) {
1558 string[] values = new string [parameters.Count];
1559 for (int i = 0; i < values.Length; ++i)
1560 values [i] = parameters [i].Name;
1561 UpdateParameters (e, "param", values);
1564 if (genericParams != null) {
1565 string[] values = new string [genericParams.Count];
1566 for (int i = 0; i < values.Length; ++i)
1567 values [i] = genericParams [i].Name;
1568 UpdateParameters (e, "typeparam", values);
1571 string retnodename = null;
1572 if (returntype != null && returntype.FullName != "System.Void") { // FIXME
1573 retnodename = returnisreturn ? "returns" : "value";
1574 string retnodename_other = !returnisreturn ? "returns" : "value";
1576 // If it has a returns node instead of a value node, change its name.
1577 XmlElement retother = (XmlElement)e.SelectSingleNode(retnodename_other);
1578 if (retother != null) {
1579 XmlElement retnode = e.OwnerDocument.CreateElement(retnodename);
1580 foreach (XmlNode node in retother)
1581 retnode.AppendChild(node.CloneNode(true));
1582 e.ReplaceChild(retnode, retother);
1584 WriteElementInitialText(e, retnodename, "To be added.");
1587 ClearElement(e, "returns");
1588 ClearElement(e, "value");
1592 WriteElementInitialText(e, "remarks", "To be added.");
1594 if (exceptions.HasValue && info.Member != null &&
1595 (exceptions.Value & ExceptionLocations.AddedMembers) == 0) {
1596 UpdateExceptions (e, info.Member);
1599 foreach (DocumentationImporter importer in importers)
1600 importer.ImportDocumentation (info);
1602 OrderDocsNodes (e, e.ChildNodes);
1603 NormalizeWhitespace(e);
1606 static readonly string[] DocsNodeOrder = {
1607 "typeparam", "param", "summary", "returns", "value", "remarks",
1610 private static void OrderDocsNodes (XmlNode docs, XmlNodeList children)
1612 MyXmlNodeList newChildren = new MyXmlNodeList (children.Count);
1613 for (int i = 0; i < DocsNodeOrder.Length; ++i) {
1614 for (int j = 0; j < children.Count; ++j) {
1615 XmlNode c = children [j];
1616 if (c.Name == DocsNodeOrder [i]) {
1617 newChildren.Add (c);
1621 if (newChildren.Count >= 0)
1622 docs.PrependChild ((XmlNode) newChildren [0]);
1623 for (int i = 1; i < newChildren.Count; ++i) {
1624 XmlNode prev = (XmlNode) newChildren [i-1];
1625 XmlNode cur = (XmlNode) newChildren [i];
1626 docs.RemoveChild (cur);
1627 docs.InsertAfter (cur, prev);
1632 private void UpdateParameters (XmlElement e, string element, string[] values)
1634 if (values != null) {
1635 XmlNode[] paramnodes = new XmlNode[values.Length];
1637 // Some documentation had param nodes with leading spaces.
1638 foreach (XmlElement paramnode in e.SelectNodes(element)){
1639 paramnode.SetAttribute("name", paramnode.GetAttribute("name").Trim());
1642 // If a member has only one parameter, we can track changes to
1643 // the name of the parameter easily.
1644 if (values.Length == 1 && e.SelectNodes(element).Count == 1) {
1645 UpdateParameterName (e, (XmlElement) e.SelectSingleNode(element), values [0]);
1648 bool reinsert = false;
1650 // Pick out existing and still-valid param nodes, and
1651 // create nodes for parameters not in the file.
1652 Hashtable seenParams = new Hashtable();
1653 for (int pi = 0; pi < values.Length; pi++) {
1654 string p = values [pi];
1657 paramnodes[pi] = e.SelectSingleNode(element + "[@name='" + p + "']");
1658 if (paramnodes[pi] != null) continue;
1660 XmlElement pe = e.OwnerDocument.CreateElement(element);
1661 pe.SetAttribute("name", p);
1662 pe.InnerText = "To be added.";
1663 paramnodes[pi] = pe;
1667 // Remove parameters that no longer exist and check all params are in the right order.
1669 MyXmlNodeList todelete = new MyXmlNodeList ();
1670 foreach (XmlElement paramnode in e.SelectNodes(element)) {
1671 string name = paramnode.GetAttribute("name");
1672 if (!seenParams.ContainsKey(name)) {
1673 if (!delete && !paramnode.InnerText.StartsWith("To be added")) {
1674 Warning ("The following param node can only be deleted if the --delete option is given: ");
1675 if (e.ParentNode == e.OwnerDocument.DocumentElement) {
1677 Warning ("\tXPath=/Type[@FullName=\"{0}\"]/Docs/param[@name=\"{1}\"]",
1678 e.OwnerDocument.DocumentElement.GetAttribute ("FullName"),
1682 Warning ("\tXPath=/Type[@FullName=\"{0}\"]//Member[@MemberName=\"{1}\"]/Docs/param[@name=\"{2}\"]",
1683 e.OwnerDocument.DocumentElement.GetAttribute ("FullName"),
1684 e.ParentNode.Attributes ["MemberName"].Value,
1687 Warning ("\tValue={0}", paramnode.OuterXml);
1689 todelete.Add (paramnode);
1694 if ((int)seenParams[name] != idx)
1700 foreach (XmlNode n in todelete) {
1701 n.ParentNode.RemoveChild (n);
1704 // Re-insert the parameter nodes at the top of the doc section.
1706 for (int pi = values.Length-1; pi >= 0; pi--)
1707 e.PrependChild(paramnodes[pi]);
1709 // Clear all existing param nodes
1710 foreach (XmlNode paramnode in e.SelectNodes(element)) {
1711 if (!delete && !paramnode.InnerText.StartsWith("To be added")) {
1712 Console.WriteLine("The following param node can only be deleted if the --delete option is given:");
1713 Console.WriteLine(paramnode.OuterXml);
1715 paramnode.ParentNode.RemoveChild(paramnode);
1721 private static void UpdateParameterName (XmlElement docs, XmlElement pe, string newName)
1723 string existingName = pe.GetAttribute ("name");
1724 pe.SetAttribute ("name", newName);
1725 if (existingName == newName)
1727 foreach (XmlElement paramref in docs.SelectNodes (".//paramref"))
1728 if (paramref.GetAttribute ("name").Trim () == existingName)
1729 paramref.SetAttribute ("name", newName);
1732 class CrefComparer : XmlNodeComparer {
1734 public CrefComparer ()
1738 public override int Compare (XmlNode x, XmlNode y)
1740 string xType = x.Attributes ["cref"].Value;
1741 string yType = y.Attributes ["cref"].Value;
1742 string xNamespace = GetNamespace (xType);
1743 string yNamespace = GetNamespace (yType);
1745 int c = xNamespace.CompareTo (yNamespace);
1748 return xType.CompareTo (yType);
1751 static string GetNamespace (string type)
1753 int n = type.LastIndexOf ('.');
1755 return type.Substring (0, n);
1756 return string.Empty;
1760 private void UpdateExceptions (XmlNode docs, IMemberReference member)
1762 foreach (var source in new ExceptionLookup (exceptions.Value)[member]) {
1763 string cref = slashdocFormatter.GetDeclaration (source.Exception);
1764 var node = docs.SelectSingleNode ("exception[@cref='" + cref + "']");
1767 XmlElement e = docs.OwnerDocument.CreateElement ("exception");
1768 e.SetAttribute ("cref", cref);
1769 e.InnerXml = "To be added; from: <see cref=\"" +
1770 string.Join ("\" />, <see cref=\"",
1771 source.Sources.Select (m => slashdocFormatter.GetDeclaration (m))
1774 docs.AppendChild (e);
1776 SortXmlNodes (docs, docs.SelectNodes ("exception"),
1777 new CrefComparer ());
1780 private static void NormalizeWhitespace(XmlElement e) {
1781 // Remove all text and whitespace nodes from the element so it
1782 // is outputted with nice indentation and no blank lines.
1783 ArrayList deleteNodes = new ArrayList();
1784 foreach (XmlNode n in e)
1785 if (n is XmlText || n is XmlWhitespace || n is XmlSignificantWhitespace)
1787 foreach (XmlNode n in deleteNodes)
1788 n.ParentNode.RemoveChild(n);
1791 private static bool UpdateAssemblyVersions (XmlElement root, IMemberReference member, bool add)
1793 TypeDefinition type = member as TypeDefinition;
1795 type = member.DeclaringType as TypeDefinition;
1796 return UpdateAssemblyVersions(root, new string[]{ GetAssemblyVersion (type.Module.Assembly) }, add);
1799 private static string GetAssemblyVersion (AssemblyDefinition assembly)
1801 return assembly.Name.Version.ToString();
1804 private static bool UpdateAssemblyVersions(XmlElement root, string[] assemblyVersions, bool add)
1806 XmlElement e = (XmlElement) root.SelectSingleNode ("AssemblyInfo");
1808 e = root.OwnerDocument.CreateElement("AssemblyInfo");
1809 root.AppendChild(e);
1811 List<XmlNode> matches = e.SelectNodes ("AssemblyVersion").Cast<XmlNode>()
1812 .Where(v => Array.IndexOf (assemblyVersions, v.InnerText) >= 0)
1814 // matches.Count > 0 && add: ignore -- already present
1815 if (matches.Count > 0 && !add) {
1816 foreach (XmlNode c in matches)
1819 else if (matches.Count == 0 && add) {
1820 foreach (string sv in assemblyVersions) {
1821 XmlElement c = root.OwnerDocument.CreateElement("AssemblyVersion");
1826 // matches.Count == 0 && !add: ignore -- already not present
1828 XmlNodeList avs = e.SelectNodes ("AssemblyVersion");
1829 SortXmlNodes (e, avs, new VersionComparer ());
1831 return avs.Count != 0;
1834 // FIXME: get TypeReferences instead of string comparison?
1835 private static string[] IgnorableAttributes = {
1836 // Security related attributes
1837 "System.Reflection.AssemblyKeyFileAttribute",
1838 "System.Reflection.AssemblyDelaySignAttribute",
1839 // Present in @RefType
1840 "System.Runtime.InteropServices.OutAttribute",
1841 // For naming the indexer to use when not using indexers
1842 "System.Reflection.DefaultMemberAttribute",
1843 // for decimal constants
1844 "System.Runtime.CompilerServices.DecimalConstantAttribute",
1845 // compiler generated code
1846 "System.Runtime.CompilerServices.CompilerGeneratedAttribute",
1847 // more compiler generated code, e.g. iterator methods
1848 "System.Diagnostics.DebuggerHiddenAttribute",
1849 "System.Runtime.CompilerServices.FixedBufferAttribute",
1850 "System.Runtime.CompilerServices.UnsafeValueTypeAttribute",
1851 // extension methods
1852 "System.Runtime.CompilerServices.ExtensionAttribute",
1855 private void MakeAttributes (XmlElement root, IEnumerable<string> attributes)
1857 if (!attributes.Any ()) {
1858 ClearElement (root, "Attributes");
1862 XmlElement e = (XmlElement)root.SelectSingleNode("Attributes");
1866 e = root.OwnerDocument.CreateElement("Attributes");
1868 foreach (string attribute in attributes) {
1869 XmlElement ae = root.OwnerDocument.CreateElement("Attribute");
1872 WriteElementText(ae, "AttributeName", attribute);
1875 if (e.ParentNode == null)
1876 root.AppendChild(e);
1878 NormalizeWhitespace(e);
1881 private static string MakeAttributesValueString (object v, TypeReference valueType)
1885 if (valueType.FullName == "System.Type")
1886 return "typeof(" + v.ToString () + ")";
1887 if (valueType.FullName == "System.String")
1888 return "\"" + v.ToString () + "\"";
1890 return (bool)v ? "true" : "false";
1891 TypeDefinition valueDef = valueType.Resolve ();
1892 if (valueDef == null || !valueDef.IsEnum)
1893 return v.ToString ();
1894 string typename = GetDocTypeFullName (valueType);
1895 var values = GetEnumerationValues (valueDef);
1896 long c = ToInt64 (v);
1897 if (values.ContainsKey (c))
1898 return typename + "." + values [c];
1899 if (valueDef.CustomAttributes.Cast<CustomAttribute> ()
1900 .Any (ca => ca.Constructor.DeclaringType.FullName == "System.FlagsAttribute")) {
1901 return string.Join (" | ",
1902 (from i in values.Keys
1904 select typename + "." + values [i])
1907 return "(" + GetDocTypeFullName (valueType) + ") " + v.ToString ();
1910 private static Dictionary<long, string> GetEnumerationValues (TypeDefinition type)
1912 var values = new Dictionary<long, string> ();
1914 (from f in type.Fields.Cast<FieldDefinition> ()
1915 where !(f.IsRuntimeSpecialName || f.IsSpecialName)
1917 values [ToInt64 (f.Constant)] = f.Name;
1922 static long ToInt64 (object value)
1925 return (long) (ulong) value;
1926 return Convert.ToInt64 (value);
1929 private void MakeParameters (XmlElement root, ParameterDefinitionCollection parameters)
1931 XmlElement e = WriteElement(root, "Parameters");
1933 foreach (ParameterDefinition p in parameters) {
1934 XmlElement pe = root.OwnerDocument.CreateElement("Parameter");
1936 pe.SetAttribute("Name", p.Name);
1937 pe.SetAttribute("Type", GetDocParameterType (p.ParameterType));
1938 if (p.ParameterType is ReferenceType) {
1939 if (p.IsOut) pe.SetAttribute("RefType", "out");
1940 else pe.SetAttribute("RefType", "ref");
1942 MakeAttributes (pe, GetCustomAttributes (p.CustomAttributes, ""));
1946 private void MakeTypeParameters (XmlElement root, GenericParameterCollection typeParams)
1948 if (typeParams == null || typeParams.Count == 0) {
1949 XmlElement f = (XmlElement) root.SelectSingleNode ("TypeParameters");
1951 root.RemoveChild (f);
1954 XmlElement e = WriteElement(root, "TypeParameters");
1956 foreach (GenericParameter t in typeParams) {
1957 XmlElement pe = root.OwnerDocument.CreateElement("TypeParameter");
1959 pe.SetAttribute("Name", t.Name);
1960 MakeAttributes (pe, GetCustomAttributes (t.CustomAttributes, ""));
1961 XmlElement ce = (XmlElement) e.SelectSingleNode ("Constraints");
1962 ConstraintCollection constraints = t.Constraints;
1963 GenericParameterAttributes attrs = t.Attributes;
1964 if (attrs == GenericParameterAttributes.NonVariant && constraints.Count == 0) {
1972 ce = root.OwnerDocument.CreateElement ("Constraints");
1974 pe.AppendChild (ce);
1975 if ((attrs & GenericParameterAttributes.Contravariant) != 0)
1976 AppendElementText (ce, "ParameterAttribute", "Contravariant");
1977 if ((attrs & GenericParameterAttributes.Covariant) != 0)
1978 AppendElementText (ce, "ParameterAttribute", "Covariant");
1979 if ((attrs & GenericParameterAttributes.DefaultConstructorConstraint) != 0)
1980 AppendElementText (ce, "ParameterAttribute", "DefaultConstructorConstraint");
1981 if ((attrs & GenericParameterAttributes.NotNullableValueTypeConstraint) != 0)
1982 AppendElementText (ce, "ParameterAttribute", "NotNullableValueTypeConstraint");
1983 if ((attrs & GenericParameterAttributes.ReferenceTypeConstraint) != 0)
1984 AppendElementText (ce, "ParameterAttribute", "ReferenceTypeConstraint");
1985 foreach (TypeReference c in constraints) {
1986 TypeDefinition cd = c.Resolve ();
1987 AppendElementText (ce,
1988 (cd != null && cd.IsInterface) ? "InterfaceName" : "BaseTypeName",
1989 GetDocTypeFullName (c));
1994 private void MakeParameters (XmlElement root, IMemberReference mi)
1996 if (mi is MethodDefinition && ((MethodDefinition) mi).IsConstructor)
1997 MakeParameters (root, ((MethodDefinition)mi).Parameters);
1998 else if (mi is MethodDefinition) {
1999 MethodDefinition mb = (MethodDefinition) mi;
2000 ParameterDefinitionCollection parameters = mb.Parameters;
2001 MakeParameters(root, parameters);
2002 if (parameters.Count > 0 && DocUtils.IsExtensionMethod (mb)) {
2003 XmlElement p = (XmlElement) root.SelectSingleNode ("Parameters/Parameter[position()=1]");
2004 p.SetAttribute ("RefType", "this");
2007 else if (mi is PropertyDefinition) {
2008 ParameterDefinitionCollection parameters = ((PropertyDefinition)mi).Parameters;
2009 if (parameters.Count > 0)
2010 MakeParameters(root, parameters);
2014 else if (mi is FieldDefinition) return;
2015 else if (mi is EventDefinition) return;
2016 else throw new ArgumentException();
2019 internal static string GetDocParameterType (TypeReference type)
2021 return GetDocTypeFullName (type).Replace ("@", "&");
2024 private void MakeReturnValue (XmlElement root, TypeReference type, CustomAttributeCollection attributes)
2026 XmlElement e = WriteElement(root, "ReturnValue");
2028 WriteElementText(e, "ReturnType", GetDocTypeFullName (type));
2029 if (attributes != null)
2030 MakeAttributes(e, GetCustomAttributes (attributes, ""));
2033 private void MakeReturnValue (XmlElement root, IMemberReference mi)
2035 if (mi is MethodDefinition && ((MethodDefinition) mi).IsConstructor)
2037 else if (mi is MethodDefinition)
2038 MakeReturnValue (root, ((MethodDefinition)mi).ReturnType.ReturnType, ((MethodDefinition)mi).ReturnType.CustomAttributes);
2039 else if (mi is PropertyDefinition)
2040 MakeReturnValue (root, ((PropertyDefinition)mi).PropertyType, null);
2041 else if (mi is FieldDefinition)
2042 MakeReturnValue (root, ((FieldDefinition)mi).FieldType, null);
2043 else if (mi is EventDefinition)
2044 MakeReturnValue (root, ((EventDefinition)mi).EventType, null);
2046 throw new ArgumentException(mi + " is a " + mi.GetType().FullName);
2049 private XmlElement MakeMember(XmlDocument doc, DocsNodeInfo info)
2051 IMemberReference mi = info.Member;
2052 if (mi is TypeDefinition) return null;
2054 string sigs = memberFormatters [0].GetDeclaration (mi);
2055 if (sigs == null) return null; // not publicly visible
2057 // no documentation for property/event accessors. Is there a better way of doing this?
2058 if (mi.Name.StartsWith("get_")) return null;
2059 if (mi.Name.StartsWith("set_")) return null;
2060 if (mi.Name.StartsWith("add_")) return null;
2061 if (mi.Name.StartsWith("remove_")) return null;
2062 if (mi.Name.StartsWith("raise_")) return null;
2064 XmlElement me = doc.CreateElement("Member");
2065 me.SetAttribute("MemberName", GetMemberName (mi));
2069 if (exceptions.HasValue &&
2070 (exceptions.Value & ExceptionLocations.AddedMembers) != 0)
2071 UpdateExceptions (info.Node, info.Member);
2073 if (since != null) {
2074 XmlNode docs = me.SelectSingleNode("Docs");
2075 docs.AppendChild (CreateSinceNode (doc));
2081 internal static string GetMemberName (IMemberReference mi)
2083 MethodDefinition mb = mi as MethodDefinition;
2085 PropertyDefinition pi = mi as PropertyDefinition;
2088 return DocUtils.GetPropertyName (pi);
2090 StringBuilder sb = new StringBuilder (mi.Name.Length);
2091 if (!DocUtils.IsExplicitlyImplemented (mb))
2092 sb.Append (mi.Name);
2094 TypeReference iface;
2095 MethodReference ifaceMethod;
2096 DocUtils.GetInfoForExplicitlyImplementedMethod (mb, out iface, out ifaceMethod);
2097 sb.Append (GetDocTypeFullName (iface));
2099 sb.Append (ifaceMethod.Name);
2101 if (mb.IsGenericMethod ()) {
2102 GenericParameterCollection typeParams = mb.GenericParameters;
2103 if (typeParams.Count > 0) {
2105 sb.Append (typeParams [0].Name);
2106 for (int i = 1; i < typeParams.Count; ++i)
2107 sb.Append (",").Append (typeParams [i].Name);
2111 return sb.ToString ();
2114 /// SIGNATURE GENERATION FUNCTIONS
2115 internal static bool IsPrivate (IMemberReference mi)
2117 return memberFormatters [0].GetDeclaration (mi) == null;
2120 internal static string GetMemberType (IMemberReference mi)
2122 if (mi is MethodDefinition && ((MethodDefinition) mi).IsConstructor)
2123 return "Constructor";
2124 if (mi is MethodDefinition)
2126 if (mi is PropertyDefinition)
2128 if (mi is FieldDefinition)
2130 if (mi is EventDefinition)
2132 throw new ArgumentException();
2135 private static string GetDocTypeName (TypeReference type)
2137 return docTypeFormatter.GetName (type);
2140 internal static string GetDocTypeFullName (TypeReference type)
2142 return DocTypeFullMemberFormatter.Default.GetName (type);
2145 internal static string GetXPathForMember (DocumentationMember member)
2147 StringBuilder xpath = new StringBuilder ();
2148 xpath.Append ("//Members/Member[@MemberName=\"")
2149 .Append (member.MemberName)
2151 if (member.Parameters != null && member.Parameters.Count > 0) {
2152 xpath.Append ("/Parameters[count(Parameter) = ")
2153 .Append (member.Parameters.Count);
2154 for (int i = 0; i < member.Parameters.Count; ++i) {
2155 xpath.Append (" and Parameter [").Append (i+1).Append ("]/@Type=\"");
2156 xpath.Append (member.Parameters [i]);
2157 xpath.Append ("\"");
2159 xpath.Append ("]/..");
2161 return xpath.ToString ();
2164 public static string GetXPathForMember (XPathNavigator member)
2166 StringBuilder xpath = new StringBuilder ();
2167 xpath.Append ("//Type[@FullName=\"")
2168 .Append (member.SelectSingleNode ("../../@FullName").Value)
2170 xpath.Append ("Members/Member[@MemberName=\"")
2171 .Append (member.SelectSingleNode ("@MemberName").Value)
2173 XPathNodeIterator parameters = member.Select ("Parameters/Parameter");
2174 if (parameters.Count > 0) {
2175 xpath.Append ("/Parameters[count(Parameter) = ")
2176 .Append (parameters.Count);
2178 while (parameters.MoveNext ()) {
2180 xpath.Append (" and Parameter [").Append (i).Append ("]/@Type=\"");
2181 xpath.Append (parameters.Current.Value);
2182 xpath.Append ("\"");
2184 xpath.Append ("]/..");
2186 return xpath.ToString ();
2189 public static string GetXPathForMember (IMemberReference member)
2191 StringBuilder xpath = new StringBuilder ();
2192 xpath.Append ("//Type[@FullName=\"")
2193 .Append (member.DeclaringType.FullName)
2195 xpath.Append ("Members/Member[@MemberName=\"")
2196 .Append (GetMemberName (member))
2199 ParameterDefinitionCollection parameters = null;
2200 if (member is MethodDefinition)
2201 parameters = ((MethodDefinition) member).Parameters;
2202 else if (member is PropertyDefinition) {
2203 parameters = ((PropertyDefinition) member).Parameters;
2205 if (parameters != null && parameters.Count > 0) {
2206 xpath.Append ("/Parameters[count(Parameter) = ")
2207 .Append (parameters.Count);
2208 for (int i = 0; i < parameters.Count; ++i) {
2209 xpath.Append (" and Parameter [").Append (i+1).Append ("]/@Type=\"");
2210 xpath.Append (GetDocParameterType (parameters [i].ParameterType));
2211 xpath.Append ("\"");
2213 xpath.Append ("]/..");
2215 return xpath.ToString ();
2219 static class CecilExtensions {
2220 public static IEnumerable<IMemberReference> GetMembers (this TypeDefinition type)
2222 foreach (var c in type.Constructors)
2223 yield return (IMemberReference) c;
2224 foreach (var e in type.Events)
2225 yield return (IMemberReference) e;
2226 foreach (var f in type.Fields)
2227 yield return (IMemberReference) f;
2228 foreach (var m in type.Methods)
2229 yield return (IMemberReference) m;
2230 foreach (var t in type.NestedTypes)
2231 yield return (IMemberReference) t;
2232 foreach (var p in type.Properties)
2233 yield return (IMemberReference) p;
2236 public static IEnumerable<IMemberReference> GetMembers (this TypeDefinition type, string member)
2238 return GetMembers (type).Where (m => m.Name == member);
2241 public static IMemberReference GetMember (this TypeDefinition type, string member)
2243 return GetMembers (type, member).EnsureZeroOrOne ();
2246 static T EnsureZeroOrOne<T> (this IEnumerable<T> source)
2248 if (source.Count () > 1)
2249 throw new InvalidOperationException ("too many matches");
2250 return source.FirstOrDefault ();
2253 public static MethodDefinition GetMethod (this TypeDefinition type, string method)
2255 return type.Methods.Cast<MethodDefinition> ()
2256 .Where (m => m.Name == method)
2257 .EnsureZeroOrOne ();
2260 public static IEnumerable<IMemberReference> GetDefaultMembers (this TypeReference type)
2262 TypeDefinition def = type as TypeDefinition;
2264 return new IMemberReference [0];
2265 CustomAttribute defMemberAttr = type.CustomAttributes.Cast<CustomAttribute> ()
2266 .Where (c => c.Constructor.DeclaringType.FullName == "System.Reflection.DefaultMemberAttribute")
2268 if (defMemberAttr == null)
2269 return new IMemberReference [0];
2270 string name = (string) defMemberAttr.ConstructorParameters [0];
2271 return def.Properties.Cast<PropertyDefinition> ()
2272 .Where (p => p.Name == name)
2273 .Select (p => (IMemberReference) p);
2276 public static IEnumerable<TypeDefinition> GetTypes (this AssemblyDefinition assembly)
2278 return assembly.Modules.Cast<ModuleDefinition> ()
2279 .SelectMany (md => md.Types.Cast<TypeDefinition> ());
2282 public static TypeDefinition GetType (this AssemblyDefinition assembly, string type)
2284 return GetTypes (assembly)
2285 .Where (td => td.FullName == type)
2286 .EnsureZeroOrOne ();
2289 public static bool IsGenericType (this TypeReference type)
2291 return type.GenericParameters.Count > 0;
2294 public static bool IsGenericMethod (this MethodReference method)
2296 return method.GenericParameters.Count > 0;
2299 public static IMemberReference Resolve (this IMemberReference member)
2301 EventReference er = member as EventReference;
2303 return er.Resolve ();
2304 FieldReference fr = member as FieldReference;
2306 return fr.Resolve ();
2307 MethodReference mr = member as MethodReference;
2309 return mr.Resolve ();
2310 PropertyReference pr = member as PropertyReference;
2312 return pr.Resolve ();
2313 TypeReference tr = member as TypeReference;
2315 return tr.Resolve ();
2316 throw new NotSupportedException ("Cannot find definition for " + member.ToString ());
2319 public static TypeReference GetUnderlyingType (this TypeDefinition type)
2323 return type.Fields.Cast<FieldDefinition>().First (f => f.Name == "value__").FieldType;
2327 static class DocUtils {
2328 public static bool IsExplicitlyImplemented (MethodDefinition method)
2330 return method.IsPrivate && method.IsFinal && method.IsVirtual;
2333 public static string GetTypeDotMember (string name)
2335 int startType, startMethod;
2336 startType = startMethod = -1;
2337 for (int i = 0; i < name.Length; ++i) {
2338 if (name [i] == '.') {
2339 startType = startMethod;
2343 return name.Substring (startType+1);
2346 public static string GetMember (string name)
2348 int i = name.LastIndexOf ('.');
2351 return name.Substring (i+1);
2354 public static void GetInfoForExplicitlyImplementedMethod (
2355 MethodDefinition method, out TypeReference iface, out MethodReference ifaceMethod)
2359 if (method.Overrides.Count != 1)
2360 throw new InvalidOperationException ("Could not determine interface type for explicitly-implemented interface member " + method.Name);
2361 iface = method.Overrides [0].DeclaringType;
2362 ifaceMethod = method.Overrides [0];
2365 public static string GetPropertyName (PropertyDefinition pi)
2367 // Issue: (g)mcs-generated assemblies that explicitly implement
2368 // properties don't specify the full namespace, just the
2369 // TypeName.Property; .NET uses Full.Namespace.TypeName.Property.
2370 MethodDefinition method = pi.GetMethod;
2372 method = pi.SetMethod;
2373 if (!IsExplicitlyImplemented (method))
2376 // Need to determine appropriate namespace for this member.
2377 TypeReference iface;
2378 MethodReference ifaceMethod;
2379 GetInfoForExplicitlyImplementedMethod (method, out iface, out ifaceMethod);
2380 return string.Join (".", new string[]{
2381 DocTypeFullMemberFormatter.Default.GetName (iface),
2382 GetMember (pi.Name)});
2385 public static string GetNamespace (TypeReference type)
2387 if (type.GetOriginalType ().IsNested)
2388 type = type.GetOriginalType ();
2389 while (type != null && type.IsNested)
2390 type = type.DeclaringType;
2392 return string.Empty;
2393 return type.Namespace;
2396 public static string PathCombine (string dir, string path)
2402 return Path.Combine (dir, path);
2405 public static bool IsExtensionMethod (MethodDefinition method)
2408 method.CustomAttributes.Cast<CustomAttribute> ()
2409 .Where (m => m.Constructor.DeclaringType.FullName == "System.Runtime.CompilerServices.ExtensionAttribute")
2411 method.DeclaringType.CustomAttributes.Cast<CustomAttribute> ()
2412 .Where (m => m.Constructor.DeclaringType.FullName == "System.Runtime.CompilerServices.ExtensionAttribute")
2416 public static bool IsDelegate (TypeDefinition type)
2418 TypeReference baseRef = type.BaseType;
2419 if (baseRef == null)
2421 return !type.IsAbstract && baseRef.FullName == "System.Delegate" || // FIXME
2422 baseRef.FullName == "System.MulticastDelegate";
2425 public static List<TypeReference> GetDeclaringTypes (TypeReference type)
2427 List<TypeReference> decls = new List<TypeReference> ();
2429 while (type.DeclaringType != null) {
2430 decls.Add (type.DeclaringType);
2431 type = type.DeclaringType;
2437 public static int GetGenericArgumentCount (TypeReference type)
2439 GenericInstanceType inst = type as GenericInstanceType;
2441 ? inst.GenericArguments.Count
2442 : type.GenericParameters.Count;
2445 public static IEnumerable<TypeReference> GetUserImplementedInterfaces (TypeDefinition type)
2447 HashSet<string> inheritedInterfaces = GetInheritedInterfaces (type);
2448 List<TypeReference> userInterfaces = new List<TypeReference> ();
2449 foreach (TypeReference iface in type.Interfaces) {
2450 TypeReference lookup = iface.Resolve () ?? iface;
2451 if (!inheritedInterfaces.Contains (GetQualifiedTypeName (lookup)))
2452 userInterfaces.Add (iface);
2454 return userInterfaces;
2457 private static string GetQualifiedTypeName (TypeReference type)
2459 return "[" + type.Scope.Name + "]" + type.FullName;
2462 private static HashSet<string> GetInheritedInterfaces (TypeDefinition type)
2464 HashSet<string> inheritedInterfaces = new HashSet<string> ();
2465 Action<TypeDefinition> a = null;
2467 if (t == null) return;
2468 foreach (TypeReference r in t.Interfaces) {
2469 inheritedInterfaces.Add (GetQualifiedTypeName (r));
2473 TypeReference baseRef = type.BaseType;
2474 while (baseRef != null) {
2475 TypeDefinition baseDef = baseRef.Resolve ();
2476 if (baseDef != null) {
2478 baseRef = baseDef.BaseType;
2483 foreach (TypeReference r in type.Interfaces)
2485 return inheritedInterfaces;
2489 class DocsNodeInfo {
2490 public DocsNodeInfo (XmlElement node)
2495 public DocsNodeInfo (XmlElement node, TypeDefinition type)
2501 public DocsNodeInfo (XmlElement node, IMemberReference member)
2504 SetMemberInfo (member);
2507 void SetType (TypeDefinition type)
2510 throw new ArgumentNullException ("type");
2512 GenericParameters = new List<GenericParameter> (type.GenericParameters.Cast<GenericParameter> ());
2513 List<TypeReference> declTypes = DocUtils.GetDeclaringTypes (type);
2514 int maxGenArgs = DocUtils.GetGenericArgumentCount (type);
2515 for (int i = 0; i < declTypes.Count - 1; ++i) {
2516 int remove = System.Math.Min (maxGenArgs,
2517 DocUtils.GetGenericArgumentCount (declTypes [i]));
2518 maxGenArgs -= remove;
2519 while (remove-- > 0)
2520 GenericParameters.RemoveAt (0);
2522 if (DocUtils.IsDelegate (type)) {
2523 Parameters = type.GetMethod("Invoke").Parameters;
2524 ReturnType = type.GetMethod("Invoke").ReturnType.ReturnType;
2525 ReturnIsReturn = true;
2529 void SetMemberInfo (IMemberReference member)
2532 throw new ArgumentNullException ("member");
2533 ReturnIsReturn = true;
2537 if (member is MethodReference ) {
2538 MethodReference mr = (MethodReference) member;
2539 Parameters = mr.Parameters;
2540 if (mr.IsGenericMethod ()) {
2541 GenericParameters = new List<GenericParameter> (mr.GenericParameters.Cast<GenericParameter> ());
2544 else if (member is PropertyDefinition) {
2545 Parameters = ((PropertyDefinition) member).Parameters;
2548 if (member is MethodDefinition) {
2549 ReturnType = ((MethodDefinition) member).ReturnType.ReturnType;
2550 } else if (member is PropertyDefinition) {
2551 ReturnType = ((PropertyDefinition) member).PropertyType;
2552 ReturnIsReturn = false;
2555 // no remarks section for enum members
2556 if (member.DeclaringType != null && ((TypeDefinition) member.DeclaringType).IsEnum)
2560 public TypeReference ReturnType;
2561 public List<GenericParameter> GenericParameters;
2562 public ParameterDefinitionCollection Parameters;
2563 public bool ReturnIsReturn;
2564 public XmlElement Node;
2565 public bool AddRemarks = true;
2566 public IMemberReference Member;
2567 public TypeDefinition Type;
2570 class DocumentationEnumerator {
2572 public virtual IEnumerable<TypeDefinition> GetDocumentationTypes (AssemblyDefinition assembly, List<string> forTypes)
2574 return GetDocumentationTypes (assembly, forTypes, null);
2577 protected IEnumerable<TypeDefinition> GetDocumentationTypes (AssemblyDefinition assembly, List<string> forTypes, HashSet<string> seen)
2579 foreach (TypeDefinition type in assembly.GetTypes()) {
2580 if (forTypes != null && forTypes.BinarySearch (type.FullName) < 0)
2582 if (seen != null && seen.Contains (type.FullName))
2585 foreach (TypeDefinition nested in type.NestedTypes)
2586 yield return nested;
2590 public virtual IEnumerable<DocsNodeInfo> GetDocumentationMembers (XmlDocument basefile, TypeDefinition type)
2592 foreach (XmlElement oldmember in basefile.SelectNodes("Type/Members/Member")) {
2593 if (oldmember.GetAttribute ("__monodocer-seen__") == "true") {
2594 oldmember.RemoveAttribute ("__monodocer-seen__");
2597 IMemberReference m = GetMember (type, new DocumentationMember (oldmember));
2599 yield return new DocsNodeInfo (oldmember);
2602 yield return new DocsNodeInfo (oldmember, m);
2607 protected static IMemberReference GetMember (TypeDefinition type, DocumentationMember member)
2609 string membertype = member.MemberType;
2611 string returntype = member.ReturnType;
2613 string docName = member.MemberName;
2614 string[] docTypeParams = GetTypeParameters (docName);
2616 // Loop through all members in this type with the same name
2617 foreach (IMemberReference mi in GetReflectionMembers (type, docName)) {
2618 if (mi is TypeDefinition) continue;
2619 if (MDocUpdater.GetMemberType(mi) != membertype) continue;
2621 if (MDocUpdater.IsPrivate (mi))
2624 ParameterDefinitionCollection pis = null;
2625 string[] typeParams = null;
2626 if (mi is MethodDefinition) {
2627 MethodDefinition mb = (MethodDefinition) mi;
2628 pis = mb.Parameters;
2629 if (docTypeParams != null && mb.IsGenericMethod ()) {
2630 GenericParameterCollection args = mb.GenericParameters;
2631 if (args.Count == docTypeParams.Length) {
2632 typeParams = args.Cast<GenericParameter> ().Select (p => p.Name).ToArray ();
2636 else if (mi is PropertyDefinition)
2637 pis = ((PropertyDefinition)mi).Parameters;
2639 int mcount = member.Parameters == null ? 0 : member.Parameters.Count;
2640 int pcount = pis == null ? 0 : pis.Count;
2641 if (mcount != pcount)
2644 MethodDefinition mDef = mi as MethodDefinition;
2645 if (mDef != null && !mDef.IsConstructor) {
2646 // Casting operators can overload based on return type.
2647 if (returntype != GetReplacedString (
2648 MDocUpdater.GetDocTypeFullName (((MethodDefinition)mi).ReturnType.ReturnType),
2649 typeParams, docTypeParams)) {
2657 for (int i = 0; i < pis.Count; i++) {
2658 string paramType = GetReplacedString (
2659 MDocUpdater.GetDocParameterType (pis [i].ParameterType),
2660 typeParams, docTypeParams);
2661 if (paramType != (string) member.Parameters [i]) {
2666 if (!good) continue;
2674 static string[] GetTypeParameters (string docName)
2676 if (docName [docName.Length-1] != '>')
2678 StringList types = new StringList ();
2679 int endToken = docName.Length-2;
2680 int i = docName.Length-2;
2682 if (docName [i] == ',' || docName [i] == '<') {
2683 types.Add (docName.Substring (i + 1, endToken - i));
2686 if (docName [i] == '<')
2691 return types.ToArray ();
2694 protected static IEnumerable<IMemberReference> GetReflectionMembers (TypeDefinition type, string docName)
2696 // need to worry about 4 forms of //@MemberName values:
2697 // 1. "Normal" (non-generic) member names: GetEnumerator
2699 // 2. Explicitly-implemented interface member names: System.Collections.IEnumerable.Current
2700 // - try as-is, and try type.member (due to "kludge" for property
2702 // 3. "Normal" Generic member names: Sort<T> (CSC)
2703 // - need to remove generic parameters --> "Sort"
2704 // 4. Explicitly-implemented interface members for generic interfaces:
2705 // -- System.Collections.Generic.IEnumerable<T>.Current
2706 // - Try as-is, and try type.member, *keeping* the generic parameters.
2707 // --> System.Collections.Generic.IEnumerable<T>.Current, IEnumerable<T>.Current
2708 // 5. As of 2008-01-02, gmcs will do e.g. 'IFoo`1[A].Method' instead of
2709 // 'IFoo<A>.Method' for explicitly implemented methods; don't interpret
2710 // this as (1) or (2).
2711 if (docName.IndexOf ('<') == -1 && docName.IndexOf ('[') == -1) {
2713 foreach (IMemberReference mi in type.GetMembers (docName))
2715 if (CountChars (docName, '.') > 0)
2716 // might be a property; try only type.member instead of
2717 // namespace.type.member.
2718 foreach (IMemberReference mi in
2719 type.GetMembers (DocUtils.GetTypeDotMember (docName)))
2726 int startLt, startType, startMethod;
2727 startLt = startType = startMethod = -1;
2728 for (int i = 0; i < docName.Length; ++i) {
2729 switch (docName [i]) {
2738 if (numLt == 0 && (i + 1) < docName.Length)
2739 // there's another character in docName, so this <...> sequence is
2740 // probably part of a generic type -- case 4.
2744 startType = startMethod;
2750 string refName = startLt == -1 ? docName : docName.Substring (0, startLt);
2752 foreach (IMemberReference mi in type.GetMembers (refName))
2756 foreach (IMemberReference mi in type.GetMembers (refName.Substring (startType + 1)))
2759 // If we _still_ haven't found it, we've hit another generic naming issue:
2760 // post Mono 1.1.18, gmcs generates [[FQTN]] instead of <TypeName> for
2761 // explicitly-implemented METHOD names (not properties), e.g.
2762 // "System.Collections.Generic.IEnumerable`1[[Foo, test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null]].GetEnumerator"
2763 // instead of "System.Collections.Generic.IEnumerable<Foo>.GetEnumerator",
2764 // which the XML docs will contain.
2766 // Alas, we can't derive the Mono name from docName, so we need to iterate
2767 // over all member names, convert them into CSC format, and compare... :-(
2770 foreach (IMemberReference mi in type.GetMembers ()) {
2771 if (MDocUpdater.GetMemberName (mi) == docName)
2776 static string GetReplacedString (string typeName, string[] from, string[] to)
2780 for (int i = 0; i < from.Length; ++i)
2781 typeName = typeName.Replace (from [i], to [i]);
2785 private static int CountChars (string s, char c)
2788 for (int i = 0; i < s.Length; ++i) {
2796 class EcmaDocumentationEnumerator : DocumentationEnumerator {
2801 public EcmaDocumentationEnumerator (MDocUpdater app, XmlReader ecmaDocs)
2804 this.ecmadocs = ecmaDocs;
2807 public override IEnumerable<TypeDefinition> GetDocumentationTypes (AssemblyDefinition assembly, List<string> forTypes)
2809 HashSet<string> seen = new HashSet<string> ();
2810 return GetDocumentationTypes (assembly, forTypes, seen)
2811 .Concat (base.GetDocumentationTypes (assembly, forTypes, seen));
2814 IEnumerable<TypeDefinition> GetDocumentationTypes (AssemblyDefinition assembly, List<string> forTypes, HashSet<string> seen)
2817 while (ecmadocs.Read ()) {
2818 switch (ecmadocs.Name) {
2820 if (typeDepth == -1)
2821 typeDepth = ecmadocs.Depth;
2822 if (ecmadocs.NodeType != XmlNodeType.Element)
2824 if (typeDepth != ecmadocs.Depth) // nested <TypeDefinition/> element?
2826 string typename = ecmadocs.GetAttribute ("FullName");
2827 string typename2 = MDocUpdater.GetTypeFileName (typename);
2828 if (forTypes != null &&
2829 forTypes.BinarySearch (typename) < 0 &&
2830 typename != typename2 &&
2831 forTypes.BinarySearch (typename2) < 0)
2834 if ((t = assembly.GetType (typename)) == null &&
2835 (t = assembly.GetType (typename2)) == null)
2837 seen.Add (typename);
2838 if (typename != typename2)
2839 seen.Add (typename2);
2840 Console.WriteLine (" Import: {0}", t.FullName);
2841 if (ecmadocs.Name != "Docs") {
2842 int depth = ecmadocs.Depth;
2843 while (ecmadocs.Read ()) {
2844 if (ecmadocs.Name == "Docs" && ecmadocs.Depth == depth + 1)
2848 if (!ecmadocs.IsStartElement ("Docs"))
2849 throw new InvalidOperationException ("Found " + ecmadocs.Name + "; expecting <Docs/>!");
2859 public override IEnumerable<DocsNodeInfo> GetDocumentationMembers (XmlDocument basefile, TypeDefinition type)
2861 return GetMembers (basefile, type)
2862 .Concat (base.GetDocumentationMembers (basefile, type));
2865 private IEnumerable<DocsNodeInfo> GetMembers (XmlDocument basefile, TypeDefinition type)
2867 while (ecmadocs.Name != "Members" && ecmadocs.Read ()) {
2870 if (ecmadocs.IsEmptyElement)
2873 int membersDepth = ecmadocs.Depth;
2875 while (go && ecmadocs.Read ()) {
2876 switch (ecmadocs.Name) {
2878 if (membersDepth != ecmadocs.Depth - 1 || ecmadocs.NodeType != XmlNodeType.Element)
2880 DocumentationMember dm = new DocumentationMember (ecmadocs);
2881 string xp = MDocUpdater.GetXPathForMember (dm);
2882 XmlElement oldmember = (XmlElement) basefile.SelectSingleNode (xp);
2884 if (oldmember == null) {
2885 m = GetMember (type, dm);
2887 app.Warning ("Could not import ECMA docs for `{0}'s `{1}': Member not found.",
2888 type.FullName, dm.MemberSignatures ["C#"]);
2889 // SelectSingleNode (ecmaDocsMember, "MemberSignature[@Language=\"C#\"]/@Value").Value);
2892 // oldmember lookup may have failed due to type parameter renames.
2894 oldmember = (XmlElement) basefile.SelectSingleNode (MDocUpdater.GetXPathForMember (m));
2895 if (oldmember == null) {
2896 XmlElement members = MDocUpdater.WriteElement (basefile.DocumentElement, "Members");
2897 oldmember = basefile.CreateElement ("Member");
2898 oldmember.SetAttribute ("MemberName", dm.MemberName);
2899 members.AppendChild (oldmember);
2900 foreach (string key in MDocUpdater.Sort (dm.MemberSignatures.Keys)) {
2901 XmlElement ms = basefile.CreateElement ("MemberSignature");
2902 ms.SetAttribute ("Language", key);
2903 ms.SetAttribute ("Value", (string) dm.MemberSignatures [key]);
2904 oldmember.AppendChild (ms);
2906 oldmember.SetAttribute ("__monodocer-seen__", "true");
2907 Console.WriteLine ("Member Added: {0}", oldmember.SelectSingleNode("MemberSignature[@Language='C#']/@Value").InnerText);
2912 m = GetMember (type, new DocumentationMember (oldmember));
2914 app.Warning ("Could not import ECMA docs for `{0}'s `{1}': Member not found.",
2915 type.FullName, dm.MemberSignatures ["C#"]);
2918 oldmember.SetAttribute ("__monodocer-seen__", "true");
2920 DocsNodeInfo node = new DocsNodeInfo (oldmember, m);
2921 if (ecmadocs.Name != "Docs")
2922 throw new InvalidOperationException ("Found " + ecmadocs.Name + "; expected <Docs/>!");
2927 if (membersDepth == ecmadocs.Depth && ecmadocs.NodeType == XmlNodeType.EndElement) {
2936 abstract class DocumentationImporter {
2938 public abstract void ImportDocumentation (DocsNodeInfo info);
2941 class MsxdocDocumentationImporter : DocumentationImporter {
2943 XmlDocument slashdocs;
2945 public MsxdocDocumentationImporter (string file)
2947 var xml = File.ReadAllText (file);
2949 // Ensure Unix line endings
2950 xml = xml.Replace ("\r", "");
2952 slashdocs = new XmlDocument();
2953 slashdocs.LoadXml (xml);
2956 public override void ImportDocumentation (DocsNodeInfo info)
2958 XmlNode elem = GetDocs (info.Member ?? info.Type);
2963 XmlElement e = info.Node;
2965 if (elem.SelectSingleNode("summary") != null)
2966 MDocUpdater.ClearElement(e, "summary");
2967 if (elem.SelectSingleNode("remarks") != null)
2968 MDocUpdater.ClearElement(e, "remarks");
2969 if (elem.SelectSingleNode ("value") != null || elem.SelectSingleNode ("returns") != null) {
2970 MDocUpdater.ClearElement(e, "value");
2971 MDocUpdater.ClearElement(e, "returns");
2974 foreach (XmlNode child in elem.ChildNodes) {
2975 switch (child.Name) {
2978 XmlAttribute name = child.Attributes ["name"];
2981 XmlElement p2 = (XmlElement) e.SelectSingleNode (child.Name + "[@name='" + name.Value + "']");
2983 p2.InnerXml = child.InnerXml;
2986 // Occasionally XML documentation will use <returns/> on
2987 // properties, so let's try to normalize things.
2990 XmlElement v = e.OwnerDocument.CreateElement (info.ReturnIsReturn ? "returns" : "value");
2991 v.InnerXml = child.InnerXml;
2997 case "permission": {
2998 XmlAttribute cref = child.Attributes ["cref"] ?? child.Attributes ["name"];
3001 XmlElement a = (XmlElement) e.SelectSingleNode (child.Name + "[@cref='" + cref.Value + "']");
3003 a = e.OwnerDocument.CreateElement (child.Name);
3004 a.SetAttribute ("cref", child.Attributes ["cref"].Value);
3007 a.InnerXml = child.InnerXml;
3011 XmlAttribute cref = child.Attributes ["cref"];
3014 XmlElement a = (XmlElement) e.SelectSingleNode ("altmember[@cref='" + cref.Value + "']");
3016 a = e.OwnerDocument.CreateElement ("altmember");
3017 a.SetAttribute ("cref", child.Attributes ["cref"].Value);
3024 if (child.NodeType == XmlNodeType.Element &&
3025 e.SelectNodes (child.Name).Cast<XmlElement>().Any (n => n.OuterXml == child.OuterXml))
3028 MDocUpdater.CopyNode (child, e);
3035 private XmlNode GetDocs (IMemberReference member)
3037 string slashdocsig = MDocUpdater.slashdocFormatter.GetDeclaration (member);
3038 if (slashdocsig != null)
3039 return slashdocs.SelectSingleNode ("doc/members/member[@name='" + slashdocsig + "']");
3044 class EcmaDocumentationImporter : DocumentationImporter {
3048 public EcmaDocumentationImporter (XmlReader ecmaDocs)
3050 this.ecmadocs = ecmaDocs;
3053 public override void ImportDocumentation (DocsNodeInfo info)
3055 if (!ecmadocs.IsStartElement ("Docs")) {
3059 XmlElement e = info.Node;
3061 int depth = ecmadocs.Depth;
3062 ecmadocs.ReadStartElement ("Docs");
3063 while (ecmadocs.Read ()) {
3064 if (ecmadocs.Name == "Docs") {
3065 if (ecmadocs.Depth == depth && ecmadocs.NodeType == XmlNodeType.EndElement)
3068 throw new InvalidOperationException ("Skipped past current <Docs/> element!");
3070 if (!ecmadocs.IsStartElement ())
3072 switch (ecmadocs.Name) {
3075 string name = ecmadocs.GetAttribute ("name");
3078 XmlNode doc = e.SelectSingleNode (
3079 ecmadocs.Name + "[@name='" + name + "']");
3080 string value = ecmadocs.ReadInnerXml ();
3082 doc.InnerXml = value.Replace ("\r", "");
3089 string name = ecmadocs.Name;
3090 string cref = ecmadocs.GetAttribute ("cref");
3093 XmlNode doc = e.SelectSingleNode (
3094 ecmadocs.Name + "[@cref='" + cref + "']");
3095 string value = ecmadocs.ReadInnerXml ().Replace ("\r", "");
3097 doc.InnerXml = value;
3099 XmlElement n = e.OwnerDocument.CreateElement (name);
3100 n.SetAttribute ("cref", cref);
3107 string name = ecmadocs.Name;
3108 string xpath = ecmadocs.Name;
3109 StringList attributes = new StringList (ecmadocs.AttributeCount);
3110 if (ecmadocs.MoveToFirstAttribute ()) {
3112 attributes.Add ("@" + ecmadocs.Name + "=\"" + ecmadocs.Value + "\"");
3113 } while (ecmadocs.MoveToNextAttribute ());
3114 ecmadocs.MoveToContent ();
3116 if (attributes.Count > 0) {
3117 xpath += "[" + string.Join (" and ", attributes.ToArray ()) + "]";
3119 XmlNode doc = e.SelectSingleNode (xpath);
3120 string value = ecmadocs.ReadInnerXml ().Replace ("\r", "");
3122 doc.InnerXml = value;
3125 XmlElement n = e.OwnerDocument.CreateElement (name);
3127 foreach (string a in attributes) {
3128 int eq = a.IndexOf ('=');
3129 n.SetAttribute (a.Substring (1, eq-1), a.Substring (eq+2, a.Length-eq-3));
3140 class DocumentationMember {
3141 public StringToStringMap MemberSignatures = new StringToStringMap ();
3142 public string ReturnType;
3143 public StringList Parameters;
3144 public string MemberName;
3145 public string MemberType;
3147 public DocumentationMember (XmlReader reader)
3149 MemberName = reader.GetAttribute ("MemberName");
3150 int depth = reader.Depth;
3152 StringList p = new StringList ();
3154 if (reader.NodeType != XmlNodeType.Element)
3156 switch (reader.Name) {
3157 case "MemberSignature":
3158 MemberSignatures [reader.GetAttribute ("Language")] = reader.GetAttribute ("Value");
3161 MemberType = reader.ReadElementString ();
3164 if (reader.Depth == depth + 2)
3165 ReturnType = reader.ReadElementString ();
3168 if (reader.Depth == depth + 2)
3169 p.Add (reader.GetAttribute ("Type"));
3172 if (reader.Depth == depth + 1)
3176 } while (go && reader.Read () && reader.Depth >= depth);
3182 public DocumentationMember (XmlNode node)
3184 MemberName = node.Attributes ["MemberName"].Value;
3185 foreach (XmlNode n in node.SelectNodes ("MemberSignature")) {
3186 XmlAttribute l = n.Attributes ["Language"];
3187 XmlAttribute v = n.Attributes ["Value"];
3188 if (l != null && v != null)
3189 MemberSignatures [l.Value] = v.Value;
3191 MemberType = node.SelectSingleNode ("MemberType").InnerText;
3192 XmlNode rt = node.SelectSingleNode ("ReturnValue/ReturnType");
3194 ReturnType = rt.InnerText;
3195 XmlNodeList p = node.SelectNodes ("Parameters/Parameter");
3197 Parameters = new StringList (p.Count);
3198 for (int i = 0; i < p.Count; ++i)
3199 Parameters.Add (p [i].Attributes ["Type"].Value);
3204 public enum MemberFormatterState {
3207 WithinGenericTypeParameters,
3210 public abstract class MemberFormatter {
3212 public virtual string Language {
3216 public virtual string GetName (IMemberReference member)
3218 TypeReference type = member as TypeReference;
3220 return GetTypeName (type);
3221 MethodReference method = member as MethodReference;
3222 if (method != null && method.Name == ".ctor") // method.IsConstructor
3223 return GetConstructorName (method);
3225 return GetMethodName (method);
3226 PropertyReference prop = member as PropertyReference;
3228 return GetPropertyName (prop);
3229 FieldReference field = member as FieldReference;
3231 return GetFieldName (field);
3232 EventReference e = member as EventReference;
3234 return GetEventName (e);
3235 throw new NotSupportedException ("Can't handle: " +
3236 (member == null ? "null" : member.GetType().ToString()));
3239 protected virtual string GetTypeName (TypeReference type)
3242 throw new ArgumentNullException ("type");
3243 return _AppendTypeName (new StringBuilder (type.Name.Length), type).ToString ();
3246 protected virtual char[] ArrayDelimeters {
3247 get {return new char[]{'[', ']'};}
3250 protected virtual MemberFormatterState MemberFormatterState { get; set; }
3252 protected StringBuilder _AppendTypeName (StringBuilder buf, TypeReference type)
3254 if (type is ArrayType) {
3255 TypeSpecification spec = type as TypeSpecification;
3256 _AppendTypeName (buf, spec != null ? spec.ElementType : type.GetOriginalType ())
3257 .Append (ArrayDelimeters [0]);
3258 var origState = MemberFormatterState;
3259 MemberFormatterState = MemberFormatterState.WithinArray;
3260 ArrayType array = (ArrayType) type;
3261 int rank = array.Rank;
3263 buf.Append (new string (',', rank-1));
3264 MemberFormatterState = origState;
3265 return buf.Append (ArrayDelimeters [1]);
3267 if (type is ReferenceType) {
3268 return AppendRefTypeName (buf, type);
3270 if (type is PointerType) {
3271 return AppendPointerTypeName (buf, type);
3273 AppendNamespace (buf, type);
3274 if (type is GenericParameter) {
3275 return AppendTypeName (buf, type);
3277 GenericInstanceType genInst = type as GenericInstanceType;
3278 if (type.GenericParameters.Count == 0 &&
3279 (genInst == null ? true : genInst.GenericArguments.Count == 0)) {
3280 return AppendFullTypeName (buf, type);
3282 return AppendGenericType (buf, type);
3285 protected virtual StringBuilder AppendNamespace (StringBuilder buf, TypeReference type)
3287 string ns = DocUtils.GetNamespace (type);
3288 if (ns != null && ns.Length > 0)
3289 buf.Append (ns).Append ('.');
3293 protected virtual StringBuilder AppendFullTypeName (StringBuilder buf, TypeReference type)
3295 if (type.DeclaringType != null)
3296 AppendFullTypeName (buf, type.DeclaringType).Append (NestedTypeSeparator);
3297 return AppendTypeName (buf, type);
3300 protected virtual StringBuilder AppendTypeName (StringBuilder buf, TypeReference type)
3302 return AppendTypeName (buf, type.Name);
3305 protected virtual StringBuilder AppendTypeName (StringBuilder buf, string typename)
3307 int n = typename.IndexOf ("`");
3309 return buf.Append (typename.Substring (0, n));
3310 return buf.Append (typename);
3313 protected virtual string RefTypeModifier {
3317 protected virtual StringBuilder AppendRefTypeName (StringBuilder buf, TypeReference type)
3319 TypeSpecification spec = type as TypeSpecification;
3320 return _AppendTypeName (buf, spec != null ? spec.ElementType : type.GetOriginalType ())
3321 .Append (RefTypeModifier);
3324 protected virtual string PointerModifier {
3328 protected virtual StringBuilder AppendPointerTypeName (StringBuilder buf, TypeReference type)
3330 TypeSpecification spec = type as TypeSpecification;
3331 return _AppendTypeName (buf, spec != null ? spec.ElementType : type.GetOriginalType ())
3332 .Append (PointerModifier);
3335 protected virtual char[] GenericTypeContainer {
3336 get {return new char[]{'<', '>'};}
3339 protected virtual char NestedTypeSeparator {
3343 protected virtual StringBuilder AppendGenericType (StringBuilder buf, TypeReference type)
3345 List<TypeReference> decls = DocUtils.GetDeclaringTypes (
3346 type is GenericInstanceType ? type.GetOriginalType () : type);
3347 List<TypeReference> genArgs = GetGenericArguments (type);
3350 bool insertNested = false;
3351 foreach (var decl in decls) {
3352 TypeReference declDef = decl.Resolve () ?? decl;
3354 buf.Append (NestedTypeSeparator);
3356 insertNested = true;
3357 AppendTypeName (buf, declDef);
3358 int ac = DocUtils.GetGenericArgumentCount (declDef);
3362 buf.Append (GenericTypeContainer [0]);
3363 var origState = MemberFormatterState;
3364 MemberFormatterState = MemberFormatterState.WithinGenericTypeParameters;
3365 _AppendTypeName (buf, genArgs [argIdx++]);
3366 for (int i = 1; i < c; ++i)
3367 _AppendTypeName (buf.Append (","), genArgs [argIdx++]);
3368 MemberFormatterState = origState;
3369 buf.Append (GenericTypeContainer [1]);
3375 protected List<TypeReference> GetGenericArguments (TypeReference type)
3377 var args = new List<TypeReference> ();
3378 GenericInstanceType inst = type as GenericInstanceType;
3380 args.AddRange (inst.GenericArguments.Cast<TypeReference> ());
3382 args.AddRange (type.GenericParameters.Cast<TypeReference> ());
3386 protected virtual StringBuilder AppendGenericTypeConstraints (StringBuilder buf, TypeReference type)
3391 protected virtual string GetConstructorName (MethodReference constructor)
3393 return constructor.Name;
3396 protected virtual string GetMethodName (MethodReference method)
3401 protected virtual string GetPropertyName (PropertyReference property)
3403 return property.Name;
3406 protected virtual string GetFieldName (FieldReference field)
3411 protected virtual string GetEventName (EventReference e)
3416 public virtual string GetDeclaration (IMemberReference member)
3419 throw new ArgumentNullException ("member");
3420 TypeDefinition type = member as TypeDefinition;
3422 return GetTypeDeclaration (type);
3423 MethodDefinition method = member as MethodDefinition;
3424 if (method != null && method.IsConstructor)
3425 return GetConstructorDeclaration (method);
3427 return GetMethodDeclaration (method);
3428 PropertyDefinition prop = member as PropertyDefinition;
3430 return GetPropertyDeclaration (prop);
3431 FieldDefinition field = member as FieldDefinition;
3433 return GetFieldDeclaration (field);
3434 EventDefinition e = member as EventDefinition;
3436 return GetEventDeclaration (e);
3437 throw new NotSupportedException ("Can't handle: " + member.GetType().ToString());
3440 protected virtual string GetTypeDeclaration (TypeDefinition type)
3443 throw new ArgumentNullException ("type");
3444 StringBuilder buf = new StringBuilder (type.Name.Length);
3445 _AppendTypeName (buf, type);
3446 AppendGenericTypeConstraints (buf, type);
3447 return buf.ToString ();
3450 protected virtual string GetConstructorDeclaration (MethodDefinition constructor)
3452 return GetConstructorName (constructor);
3455 protected virtual string GetMethodDeclaration (MethodDefinition method)
3457 // Special signature for destructors.
3458 if (method.Name == "Finalize" && method.Parameters.Count == 0)
3459 return GetFinalizerName (method);
3461 StringBuilder buf = new StringBuilder ();
3463 AppendVisibility (buf, method);
3464 if (buf.Length == 0 &&
3465 !(DocUtils.IsExplicitlyImplemented (method) && !method.IsSpecialName))
3468 AppendModifiers (buf, method);
3470 if (buf.Length != 0)
3472 buf.Append (GetName (method.ReturnType.ReturnType)).Append (" ");
3474 AppendMethodName (buf, method);
3475 AppendGenericMethod (buf, method).Append (" ");
3476 AppendParameters (buf, method, method.Parameters);
3477 AppendGenericMethodConstraints (buf, method);
3478 return buf.ToString ();
3481 protected virtual StringBuilder AppendMethodName (StringBuilder buf, MethodDefinition method)
3483 return buf.Append (method.Name);
3486 protected virtual string GetFinalizerName (MethodDefinition method)
3491 protected virtual StringBuilder AppendVisibility (StringBuilder buf, MethodDefinition method)
3496 protected virtual StringBuilder AppendModifiers (StringBuilder buf, MethodDefinition method)
3501 protected virtual StringBuilder AppendGenericMethod (StringBuilder buf, MethodDefinition method)
3506 protected virtual StringBuilder AppendParameters (StringBuilder buf, MethodDefinition method, ParameterDefinitionCollection parameters)
3511 protected virtual StringBuilder AppendGenericMethodConstraints (StringBuilder buf, MethodDefinition method)
3516 protected virtual string GetPropertyDeclaration (PropertyDefinition property)
3518 return GetPropertyName (property);
3521 protected virtual string GetFieldDeclaration (FieldDefinition field)
3523 return GetFieldName (field);
3526 protected virtual string GetEventDeclaration (EventDefinition e)
3528 return GetEventName (e);
3532 class ILFullMemberFormatter : MemberFormatter {
3534 public override string Language {
3535 get {return "ILAsm";}
3538 protected override char NestedTypeSeparator {
3544 protected override StringBuilder AppendNamespace (StringBuilder buf, TypeReference type)
3546 if (GetBuiltinType (type.FullName) != null)
3548 string ns = DocUtils.GetNamespace (type);
3549 if (ns != null && ns.Length > 0) {
3550 if (type.IsValueType)
3551 buf.Append ("valuetype ");
3553 buf.Append ("class ");
3554 buf.Append (ns).Append ('.');
3559 private static string GetBuiltinType (string t)
3562 case "System.Byte": return "unsigned int8";
3563 case "System.SByte": return "int8";
3564 case "System.Int16": return "int16";
3565 case "System.Int32": return "int32";
3566 case "System.Int64": return "int64";
3567 case "System.IntPtr": return "native int";
3569 case "System.UInt16": return "unsigned int16";
3570 case "System.UInt32": return "unsigned int32";
3571 case "System.UInt64": return "unsigned int64";
3572 case "System.UIntPtr": return "native unsigned int";
3574 case "System.Single": return "float32";
3575 case "System.Double": return "float64";
3576 case "System.Boolean": return "bool";
3577 case "System.Char": return "char";
3578 case "System.Void": return "void";
3579 case "System.String": return "string";
3580 case "System.Object": return "object";
3585 protected override StringBuilder AppendTypeName (StringBuilder buf, string typename)
3587 return buf.Append (typename);
3590 protected override StringBuilder AppendTypeName (StringBuilder buf, TypeReference type)
3592 var gp = type as GenericParameter;
3593 if (type is GenericParameter)
3594 return AppendGenericParameterConstraints (buf, (GenericParameter) type).Append (type.Name);
3596 string s = GetBuiltinType (type.FullName);
3598 return buf.Append (s);
3599 return base.AppendTypeName (buf, type);
3602 private StringBuilder AppendGenericParameterConstraints (StringBuilder buf, GenericParameter type)
3604 if (MemberFormatterState != MemberFormatterState.WithinGenericTypeParameters) {
3605 return buf.Append (type.Owner is TypeReference ? "!" : "!!");
3607 GenericParameterAttributes attrs = type.Attributes;
3608 if ((attrs & GenericParameterAttributes.ReferenceTypeConstraint) != 0)
3609 buf.Append ("class ");
3610 if ((attrs & GenericParameterAttributes.NotNullableValueTypeConstraint) != 0)
3611 buf.Append ("struct ");
3612 if ((attrs & GenericParameterAttributes.DefaultConstructorConstraint) != 0)
3613 buf.Append (".ctor ");
3614 ConstraintCollection constraints = type.Constraints;
3615 MemberFormatterState = 0;
3616 if (constraints.Count > 0) {
3617 var full = new ILFullMemberFormatter ();
3618 buf.Append ("(").Append (full.GetName (constraints [0]));
3619 for (int i = 1; i < constraints.Count; ++i) {
3620 buf.Append (", ").Append (full.GetName (constraints [i]));
3624 MemberFormatterState = MemberFormatterState.WithinGenericTypeParameters;
3626 if ((attrs & GenericParameterAttributes.Covariant) != 0)
3628 if ((attrs & GenericParameterAttributes.Contravariant) != 0)
3633 protected override string GetTypeDeclaration (TypeDefinition type)
3635 string visibility = GetTypeVisibility (type.Attributes);
3636 if (visibility == null)
3639 StringBuilder buf = new StringBuilder ();
3641 buf.Append (".class ");
3643 buf.Append ("nested ");
3644 buf.Append (visibility).Append (" ");
3645 if (type.IsInterface)
3646 buf.Append ("interface ");
3647 if (type.IsSequentialLayout)
3648 buf.Append ("sequential ");
3649 if (type.IsAutoLayout)
3650 buf.Append ("auto ");
3651 if (type.IsAnsiClass)
3652 buf.Append ("ansi ");
3653 if (type.IsAbstract)
3654 buf.Append ("abstract ");
3655 if (type.IsSerializable)
3656 buf.Append ("serializable ");
3658 buf.Append ("sealed ");
3659 if (type.IsBeforeFieldInit)
3660 buf.Append ("beforefieldinit ");
3661 var state = MemberFormatterState;
3662 MemberFormatterState = MemberFormatterState.WithinGenericTypeParameters;
3663 buf.Append (GetName (type));
3664 MemberFormatterState = state;
3665 var full = new ILFullMemberFormatter ();
3666 if (type.BaseType != null) {
3667 buf.Append (" extends ");
3668 if (type.BaseType.FullName == "System.Object")
3669 buf.Append ("System.Object");
3671 buf.Append (full.GetName (type.BaseType).Substring ("class ".Length));
3674 foreach (var name in type.Interfaces.Cast<TypeReference>()
3675 .Select (i => full.GetName (i))
3676 .OrderBy (n => n)) {
3678 buf.Append (" implements ");
3687 return buf.ToString ();
3690 protected override StringBuilder AppendGenericType (StringBuilder buf, TypeReference type)
3692 List<TypeReference> decls = DocUtils.GetDeclaringTypes (
3693 type is GenericInstanceType ? type.GetOriginalType () : type);
3695 foreach (var decl in decls) {
3696 TypeReference declDef = decl.Resolve () ?? decl;
3698 buf.Append (NestedTypeSeparator);
3701 AppendTypeName (buf, declDef);
3705 foreach (TypeReference arg in GetGenericArguments (type)) {
3709 _AppendTypeName (buf, arg);
3715 static string GetTypeVisibility (TypeAttributes ta)
3717 switch (ta & TypeAttributes.VisibilityMask) {
3718 case TypeAttributes.Public:
3719 case TypeAttributes.NestedPublic:
3722 case TypeAttributes.NestedFamily:
3723 case TypeAttributes.NestedFamORAssem:
3731 protected override string GetConstructorDeclaration (MethodDefinition constructor)
3733 return GetMethodDeclaration (constructor);
3736 protected override string GetMethodDeclaration (MethodDefinition method)
3738 if (method.IsPrivate && !DocUtils.IsExplicitlyImplemented (method))
3741 var buf = new StringBuilder ();
3742 buf.Append (".method ");
3743 AppendVisibility (buf, method);
3744 if (method.IsStatic)
3745 buf.Append ("static ");
3746 if (method.IsHideBySig)
3747 buf.Append ("hidebysig ");
3748 if (method.IsPInvokeImpl) {
3749 var info = method.PInvokeInfo;
3750 buf.Append ("pinvokeimpl (\"")
3751 .Append (info.Module.Name)
3752 .Append ("\" as \"")
3753 .Append (info.EntryPoint)
3755 if (info.IsCharSetAuto)
3756 buf.Append (" auto");
3757 if (info.IsCharSetUnicode)
3758 buf.Append (" unicode");
3759 if (info.IsCharSetAnsi)
3760 buf.Append (" ansi");
3761 if (info.IsCallConvCdecl)
3762 buf.Append (" cdecl");
3763 if (info.IsCallConvStdCall)
3764 buf.Append (" stdcall");
3765 if (info.IsCallConvWinapi)
3766 buf.Append (" winapi");
3767 if (info.IsCallConvThiscall)
3768 buf.Append (" thiscall");
3769 if (info.SupportsLastError)
3770 buf.Append (" lasterr");
3773 if (method.IsSpecialName)
3774 buf.Append ("specialname ");
3775 if (method.IsRuntimeSpecialName)
3776 buf.Append ("rtspecialname ");
3777 if (method.IsNewSlot)
3778 buf.Append ("newslot ");
3779 if (method.IsVirtual)
3780 buf.Append ("virtual ");
3781 if (!method.IsStatic)
3782 buf.Append ("instance ");
3783 _AppendTypeName (buf, method.ReturnType.ReturnType);
3785 .Append (method.Name);
3786 if (method.IsGenericMethod ()) {
3787 var state = MemberFormatterState;
3788 MemberFormatterState = MemberFormatterState.WithinGenericTypeParameters;
3789 GenericParameterCollection args = method.GenericParameters;
3790 if (args.Count > 0) {
3792 _AppendTypeName (buf, args [0]);
3793 for (int i = 1; i < args.Count; ++i)
3794 _AppendTypeName (buf.Append (", "), args [i]);
3797 MemberFormatterState = state;
3802 for (int i = 0; i < method.Parameters.Count; ++i) {
3806 _AppendTypeName (buf, method.Parameters [i].ParameterType);
3808 buf.Append (method.Parameters [i].Name);
3812 buf.Append (" cil");
3813 if (method.IsRuntime)
3814 buf.Append (" runtime");
3815 if (method.IsManaged)
3816 buf.Append (" managed");
3818 return buf.ToString ();
3821 protected override StringBuilder AppendMethodName (StringBuilder buf, MethodDefinition method)
3823 if (DocUtils.IsExplicitlyImplemented (method)) {
3824 TypeReference iface;
3825 MethodReference ifaceMethod;
3826 DocUtils.GetInfoForExplicitlyImplementedMethod (method, out iface, out ifaceMethod);
3827 return buf.Append (new CSharpMemberFormatter ().GetName (iface))
3829 .Append (ifaceMethod.Name);
3831 return base.AppendMethodName (buf, method);
3834 protected override string RefTypeModifier {
3838 protected override StringBuilder AppendVisibility (StringBuilder buf, MethodDefinition method)
3840 if (method.IsPublic)
3841 return buf.Append ("public ");
3842 if (method.IsFamilyAndAssembly)
3843 return buf.Append ("familyandassembly");
3844 if (method.IsFamilyOrAssembly)
3845 return buf.Append ("familyorassembly");
3846 if (method.IsFamily)
3847 return buf.Append ("family");
3851 protected override StringBuilder AppendModifiers (StringBuilder buf, MethodDefinition method)
3853 string modifiers = String.Empty;
3854 if (method.IsStatic) modifiers += " static";
3855 if (method.IsVirtual && !method.IsAbstract) {
3856 if ((method.Attributes & MethodAttributes.NewSlot) != 0) modifiers += " virtual";
3857 else modifiers += " override";
3859 TypeDefinition declType = (TypeDefinition) method.DeclaringType;
3860 if (method.IsAbstract && !declType.IsInterface) modifiers += " abstract";
3861 if (method.IsFinal) modifiers += " sealed";
3862 if (modifiers == " virtual sealed") modifiers = "";
3864 return buf.Append (modifiers);
3867 protected override StringBuilder AppendGenericMethod (StringBuilder buf, MethodDefinition method)
3869 if (method.IsGenericMethod ()) {
3870 GenericParameterCollection args = method.GenericParameters;
3871 if (args.Count > 0) {
3873 buf.Append (args [0].Name);
3874 for (int i = 1; i < args.Count; ++i)
3875 buf.Append (",").Append (args [i].Name);
3882 protected override StringBuilder AppendParameters (StringBuilder buf, MethodDefinition method, ParameterDefinitionCollection parameters)
3884 return AppendParameters (buf, method, parameters, '(', ')');
3887 private StringBuilder AppendParameters (StringBuilder buf, MethodDefinition method, ParameterDefinitionCollection parameters, char begin, char end)
3891 if (parameters.Count > 0) {
3892 if (DocUtils.IsExtensionMethod (method))
3893 buf.Append ("this ");
3894 AppendParameter (buf, parameters [0]);
3895 for (int i = 1; i < parameters.Count; ++i) {
3897 AppendParameter (buf, parameters [i]);
3901 return buf.Append (end);
3904 private StringBuilder AppendParameter (StringBuilder buf, ParameterDefinition parameter)
3906 if (parameter.ParameterType is ReferenceType) {
3907 if (parameter.IsOut)
3908 buf.Append ("out ");
3910 buf.Append ("ref ");
3912 buf.Append (GetName (parameter.ParameterType)).Append (" ");
3913 return buf.Append (parameter.Name);
3916 protected override string GetPropertyDeclaration (PropertyDefinition property)
3918 MethodDefinition gm = null, sm = null;
3920 string get_visible = null;
3921 if ((gm = property.GetMethod) != null &&
3922 (DocUtils.IsExplicitlyImplemented (gm) ||
3923 (!gm.IsPrivate && !gm.IsAssembly && !gm.IsFamilyAndAssembly)))
3924 get_visible = AppendVisibility (new StringBuilder (), gm).ToString ();
3925 string set_visible = null;
3926 if ((sm = property.SetMethod) != null &&
3927 (DocUtils.IsExplicitlyImplemented (sm) ||
3928 (!sm.IsPrivate && !sm.IsAssembly && !sm.IsFamilyAndAssembly)))
3929 set_visible = AppendVisibility (new StringBuilder (), sm).ToString ();
3931 if ((set_visible == null) && (get_visible == null))
3935 StringBuilder buf = new StringBuilder ()
3936 .Append (".property ");
3937 if (!(gm ?? sm).IsStatic)
3938 buf.Append ("instance ");
3939 _AppendTypeName (buf, property.PropertyType);
3940 buf.Append (' ').Append (property.Name);
3941 if (!property.HasParameters || property.Parameters.Count == 0)
3942 return buf.ToString ();
3946 foreach (ParameterDefinition p in property.Parameters) {
3950 _AppendTypeName (buf, p.ParameterType);
3954 return buf.ToString ();
3957 protected override string GetFieldDeclaration (FieldDefinition field)
3959 TypeDefinition declType = (TypeDefinition) field.DeclaringType;
3960 if (declType.IsEnum && field.Name == "value__")
3961 return null; // This member of enums aren't documented.
3963 StringBuilder buf = new StringBuilder ();
3964 AppendFieldVisibility (buf, field);
3965 if (buf.Length == 0)
3968 buf.Insert (0, ".field ");
3971 buf.Append ("static ");
3972 if (field.IsInitOnly)
3973 buf.Append ("initonly ");
3974 if (field.IsLiteral)
3975 buf.Append ("literal ");
3976 _AppendTypeName (buf, field.FieldType);
3977 buf.Append (' ').Append (field.Name);
3978 AppendFieldValue (buf, field);
3980 return buf.ToString ();
3983 static StringBuilder AppendFieldVisibility (StringBuilder buf, FieldDefinition field)
3986 return buf.Append ("public ");
3987 if (field.IsFamilyAndAssembly)
3988 return buf.Append ("familyandassembly ");
3989 if (field.IsFamilyOrAssembly)
3990 return buf.Append ("familyorassembly ");
3992 return buf.Append ("family ");
3996 static StringBuilder AppendFieldValue (StringBuilder buf, FieldDefinition field)
3998 // enums have a value__ field, which we ignore
3999 if (field.DeclaringType.IsGenericType ())
4001 if (field.HasConstant && field.IsLiteral) {
4004 val = field.Constant;
4009 buf.Append (" = ").Append ("null");
4010 else if (val is Enum)
4012 .Append (GetBuiltinType (field.DeclaringType.GetUnderlyingType ().FullName))
4014 .Append (val.ToString ())
4016 else if (val is IFormattable) {
4017 string value = ((IFormattable)val).ToString();
4020 buf.Append ("\"" + value + "\"");
4022 buf.Append (GetBuiltinType (field.DeclaringType.GetUnderlyingType ().FullName))
4031 protected override string GetEventDeclaration (EventDefinition e)
4033 StringBuilder buf = new StringBuilder ();
4034 if (AppendVisibility (buf, e.AddMethod).Length == 0) {
4039 buf.Append (".event ")
4040 .Append (GetName (e.EventType))
4044 return buf.ToString ();
4048 class ILMemberFormatter : ILFullMemberFormatter {
4049 protected override StringBuilder AppendNamespace (StringBuilder buf, TypeReference type)
4055 class CSharpFullMemberFormatter : MemberFormatter {
4057 public override string Language {
4061 protected override StringBuilder AppendNamespace (StringBuilder buf, TypeReference type)
4063 string ns = DocUtils.GetNamespace (type);
4064 if (GetCSharpType (type.FullName) == null && ns != null && ns.Length > 0 && ns != "System")
4065 buf.Append (ns).Append ('.');
4069 private string GetCSharpType (string t)
4072 case "System.Byte": return "byte";
4073 case "System.SByte": return "sbyte";
4074 case "System.Int16": return "short";
4075 case "System.Int32": return "int";
4076 case "System.Int64": return "long";
4078 case "System.UInt16": return "ushort";
4079 case "System.UInt32": return "uint";
4080 case "System.UInt64": return "ulong";
4082 case "System.Single": return "float";
4083 case "System.Double": return "double";
4084 case "System.Decimal": return "decimal";
4085 case "System.Boolean": return "bool";
4086 case "System.Char": return "char";
4087 case "System.Void": return "void";
4088 case "System.String": return "string";
4089 case "System.Object": return "object";
4094 protected override StringBuilder AppendTypeName (StringBuilder buf, TypeReference type)
4096 if (type is GenericParameter)
4097 return AppendGenericParameterConstraints (buf, (GenericParameter) type).Append (type.Name);
4098 string t = type.FullName;
4099 if (!t.StartsWith ("System.")) {
4100 return base.AppendTypeName (buf, type);
4103 string s = GetCSharpType (t);
4105 return buf.Append (s);
4107 return base.AppendTypeName (buf, type);
4110 private StringBuilder AppendGenericParameterConstraints (StringBuilder buf, GenericParameter type)
4112 if (MemberFormatterState != MemberFormatterState.WithinGenericTypeParameters)
4114 GenericParameterAttributes attrs = type.Attributes;
4115 bool isout = (attrs & GenericParameterAttributes.Covariant) != 0;
4116 bool isin = (attrs & GenericParameterAttributes.Contravariant) != 0;
4120 buf.Append ("out ");
4124 protected override string GetTypeDeclaration (TypeDefinition type)
4126 string visibility = GetTypeVisibility (type.Attributes);
4127 if (visibility == null)
4130 StringBuilder buf = new StringBuilder ();
4132 buf.Append (visibility);
4135 MemberFormatter full = new CSharpFullMemberFormatter ();
4137 if (DocUtils.IsDelegate (type)) {
4138 buf.Append("delegate ");
4139 MethodDefinition invoke = type.GetMethod ("Invoke");
4140 buf.Append (full.GetName (invoke.ReturnType.ReturnType)).Append (" ");
4141 buf.Append (GetName (type));
4142 AppendParameters (buf, invoke, invoke.Parameters);
4143 AppendGenericTypeConstraints (buf, type);
4146 return buf.ToString();
4149 if (type.IsAbstract && !type.IsInterface)
4150 buf.Append("abstract ");
4151 if (type.IsSealed && !DocUtils.IsDelegate (type) && !type.IsValueType)
4152 buf.Append("sealed ");
4153 buf.Replace ("abstract sealed", "static");
4155 buf.Append (GetTypeKind (type));
4157 buf.Append (GetCSharpType (type.FullName) == null
4162 TypeReference basetype = type.BaseType;
4163 if (basetype != null && basetype.FullName == "System.Object" || type.IsValueType) // FIXME
4166 List<string> interface_names = DocUtils.GetUserImplementedInterfaces (type)
4167 .Select (iface => full.GetName (iface))
4171 if (basetype != null || interface_names.Count > 0)
4174 if (basetype != null) {
4175 buf.Append (full.GetName (basetype));
4176 if (interface_names.Count > 0)
4180 for (int i = 0; i < interface_names.Count; i++){
4183 buf.Append (interface_names [i]);
4185 AppendGenericTypeConstraints (buf, type);
4188 return buf.ToString ();
4191 static string GetTypeKind (TypeDefinition t)
4197 if (t.IsClass || t.FullName == "System.Enum")
4201 throw new ArgumentException(t.FullName);
4204 static string GetTypeVisibility (TypeAttributes ta)
4206 switch (ta & TypeAttributes.VisibilityMask) {
4207 case TypeAttributes.Public:
4208 case TypeAttributes.NestedPublic:
4211 case TypeAttributes.NestedFamily:
4212 case TypeAttributes.NestedFamORAssem:
4220 protected override StringBuilder AppendGenericTypeConstraints (StringBuilder buf, TypeReference type)
4222 if (type.GenericParameters.Count == 0)
4224 return AppendConstraints (buf, type.GenericParameters);
4227 private StringBuilder AppendConstraints (StringBuilder buf, GenericParameterCollection genArgs)
4229 foreach (GenericParameter genArg in genArgs) {
4230 GenericParameterAttributes attrs = genArg.Attributes;
4231 ConstraintCollection constraints = genArg.Constraints;
4232 if (attrs == GenericParameterAttributes.NonVariant && constraints.Count == 0)
4235 bool isref = (attrs & GenericParameterAttributes.ReferenceTypeConstraint) != 0;
4236 bool isvt = (attrs & GenericParameterAttributes.NotNullableValueTypeConstraint) != 0;
4237 bool isnew = (attrs & GenericParameterAttributes.DefaultConstructorConstraint) != 0;
4240 if (!isref && !isvt && !isnew && constraints.Count == 0)
4242 buf.Append (" where ").Append (genArg.Name).Append (" : ");
4244 buf.Append ("class");
4248 buf.Append ("struct");
4251 if (constraints.Count > 0 && !isvt) {
4254 buf.Append (GetTypeName (constraints [0]));
4255 for (int i = 1; i < constraints.Count; ++i)
4256 buf.Append (", ").Append (GetTypeName (constraints [i]));
4258 if (isnew && !isvt) {
4261 buf.Append ("new()");
4267 protected override string GetConstructorDeclaration (MethodDefinition constructor)
4269 StringBuilder buf = new StringBuilder ();
4270 AppendVisibility (buf, constructor);
4271 if (buf.Length == 0)
4275 base.AppendTypeName (buf, constructor.DeclaringType.Name).Append (' ');
4276 AppendParameters (buf, constructor, constructor.Parameters);
4279 return buf.ToString ();
4282 protected override string GetMethodDeclaration (MethodDefinition method)
4284 string decl = base.GetMethodDeclaration (method);
4290 protected override StringBuilder AppendMethodName (StringBuilder buf, MethodDefinition method)
4292 if (DocUtils.IsExplicitlyImplemented (method)) {
4293 TypeReference iface;
4294 MethodReference ifaceMethod;
4295 DocUtils.GetInfoForExplicitlyImplementedMethod (method, out iface, out ifaceMethod);
4296 return buf.Append (new CSharpMemberFormatter ().GetName (iface))
4298 .Append (ifaceMethod.Name);
4300 return base.AppendMethodName (buf, method);
4303 protected override StringBuilder AppendGenericMethodConstraints (StringBuilder buf, MethodDefinition method)
4305 if (method.GenericParameters.Count == 0)
4307 return AppendConstraints (buf, method.GenericParameters);
4310 protected override string RefTypeModifier {
4314 protected override string GetFinalizerName (MethodDefinition method)
4316 return "~" + method.DeclaringType.Name + " ()";
4319 protected override StringBuilder AppendVisibility (StringBuilder buf, MethodDefinition method)
4323 if (method.IsPublic)
4324 return buf.Append ("public");
4325 if (method.IsFamily || method.IsFamilyOrAssembly)
4326 return buf.Append ("protected");
4330 protected override StringBuilder AppendModifiers (StringBuilder buf, MethodDefinition method)
4332 string modifiers = String.Empty;
4333 if (method.IsStatic) modifiers += " static";
4334 if (method.IsVirtual && !method.IsAbstract) {
4335 if ((method.Attributes & MethodAttributes.NewSlot) != 0) modifiers += " virtual";
4336 else modifiers += " override";
4338 TypeDefinition declType = (TypeDefinition) method.DeclaringType;
4339 if (method.IsAbstract && !declType.IsInterface) modifiers += " abstract";
4340 if (method.IsFinal) modifiers += " sealed";
4341 if (modifiers == " virtual sealed") modifiers = "";
4343 return buf.Append (modifiers);
4346 protected override StringBuilder AppendGenericMethod (StringBuilder buf, MethodDefinition method)
4348 if (method.IsGenericMethod ()) {
4349 GenericParameterCollection args = method.GenericParameters;
4350 if (args.Count > 0) {
4352 buf.Append (args [0].Name);
4353 for (int i = 1; i < args.Count; ++i)
4354 buf.Append (",").Append (args [i].Name);
4361 protected override StringBuilder AppendParameters (StringBuilder buf, MethodDefinition method, ParameterDefinitionCollection parameters)
4363 return AppendParameters (buf, method, parameters, '(', ')');
4366 private StringBuilder AppendParameters (StringBuilder buf, MethodDefinition method, ParameterDefinitionCollection parameters, char begin, char end)
4370 if (parameters.Count > 0) {
4371 if (DocUtils.IsExtensionMethod (method))
4372 buf.Append ("this ");
4373 AppendParameter (buf, parameters [0]);
4374 for (int i = 1; i < parameters.Count; ++i) {
4376 AppendParameter (buf, parameters [i]);
4380 return buf.Append (end);
4383 private StringBuilder AppendParameter (StringBuilder buf, ParameterDefinition parameter)
4385 if (parameter.ParameterType is ReferenceType) {
4386 if (parameter.IsOut)
4387 buf.Append ("out ");
4389 buf.Append ("ref ");
4391 buf.Append (GetName (parameter.ParameterType)).Append (" ");
4392 return buf.Append (parameter.Name);
4395 protected override string GetPropertyDeclaration (PropertyDefinition property)
4397 MethodDefinition method;
4399 string get_visible = null;
4400 if ((method = property.GetMethod) != null &&
4401 (DocUtils.IsExplicitlyImplemented (method) ||
4402 (!method.IsPrivate && !method.IsAssembly && !method.IsFamilyAndAssembly)))
4403 get_visible = AppendVisibility (new StringBuilder (), method).ToString ();
4404 string set_visible = null;
4405 if ((method = property.SetMethod) != null &&
4406 (DocUtils.IsExplicitlyImplemented (method) ||
4407 (!method.IsPrivate && !method.IsAssembly && !method.IsFamilyAndAssembly)))
4408 set_visible = AppendVisibility (new StringBuilder (), method).ToString ();
4410 if ((set_visible == null) && (get_visible == null))
4414 StringBuilder buf = new StringBuilder ();
4415 if (get_visible != null && (set_visible == null || (set_visible != null && get_visible == set_visible)))
4416 buf.Append (visibility = get_visible);
4417 else if (set_visible != null && get_visible == null)
4418 buf.Append (visibility = set_visible);
4420 buf.Append (visibility = "public");
4422 // Pick an accessor to use for static/virtual/override/etc. checks.
4423 method = property.SetMethod;
4425 method = property.GetMethod;
4427 string modifiers = String.Empty;
4428 if (method.IsStatic) modifiers += " static";
4429 if (method.IsVirtual && !method.IsAbstract) {
4430 if ((method.Attributes & MethodAttributes.NewSlot) != 0)
4431 modifiers += " virtual";
4433 modifiers += " override";
4435 TypeDefinition declDef = (TypeDefinition) method.DeclaringType;
4436 if (method.IsAbstract && !declDef.IsInterface)
4437 modifiers += " abstract";
4439 modifiers += " sealed";
4440 if (modifiers == " virtual sealed")
4442 buf.Append (modifiers).Append (' ');
4444 buf.Append (GetName (property.PropertyType)).Append (' ');
4446 IEnumerable<IMemberReference> defs = property.DeclaringType.GetDefaultMembers ();
4447 string name = property.Name;
4448 foreach (IMemberReference mi in defs) {
4449 if (mi == property) {
4454 buf.Append (name == "this" ? name : DocUtils.GetPropertyName (property));
4456 if (property.Parameters.Count != 0) {
4457 AppendParameters (buf, method, property.Parameters, '[', ']');
4461 if (set_visible != null) {
4462 if (set_visible != visibility)
4463 buf.Append (' ').Append (set_visible);
4464 buf.Append (" set;");
4466 if (get_visible != null) {
4467 if (get_visible != visibility)
4468 buf.Append (' ').Append (get_visible);
4469 buf.Append (" get;");
4473 return buf [0] != ' ' ? buf.ToString () : buf.ToString (1, buf.Length-1);
4476 protected override string GetFieldDeclaration (FieldDefinition field)
4478 TypeDefinition declType = (TypeDefinition) field.DeclaringType;
4479 if (declType.IsEnum && field.Name == "value__")
4480 return null; // This member of enums aren't documented.
4482 StringBuilder buf = new StringBuilder ();
4483 AppendFieldVisibility (buf, field);
4484 if (buf.Length == 0)
4487 if (declType.IsEnum)
4490 if (field.IsStatic && !field.IsLiteral)
4491 buf.Append (" static");
4492 if (field.IsInitOnly)
4493 buf.Append (" readonly");
4494 if (field.IsLiteral)
4495 buf.Append (" const");
4497 buf.Append (' ').Append (GetName (field.FieldType)).Append (' ');
4498 buf.Append (field.Name);
4499 AppendFieldValue (buf, field);
4502 return buf.ToString ();
4505 static StringBuilder AppendFieldVisibility (StringBuilder buf, FieldDefinition field)
4508 return buf.Append ("public");
4509 if (field.IsFamily || field.IsFamilyOrAssembly)
4510 return buf.Append ("protected");
4514 static StringBuilder AppendFieldValue (StringBuilder buf, FieldDefinition field)
4516 // enums have a value__ field, which we ignore
4517 if (((TypeDefinition ) field.DeclaringType).IsEnum ||
4518 field.DeclaringType.IsGenericType ())
4520 if (field.HasConstant && field.IsLiteral) {
4523 val = field.Constant;
4528 buf.Append (" = ").Append ("null");
4529 else if (val is Enum)
4530 buf.Append (" = ").Append (val.ToString ());
4531 else if (val is IFormattable) {
4532 string value = ((IFormattable)val).ToString();
4534 value = "\"" + value + "\"";
4535 buf.Append (" = ").Append (value);
4541 protected override string GetEventDeclaration (EventDefinition e)
4543 StringBuilder buf = new StringBuilder ();
4544 if (AppendVisibility (buf, e.AddMethod).Length == 0) {
4548 AppendModifiers (buf, e.AddMethod);
4550 buf.Append (" event ");
4551 buf.Append (GetName (e.EventType)).Append (' ');
4552 buf.Append (e.Name).Append (';');
4554 return buf.ToString ();
4558 class CSharpMemberFormatter : CSharpFullMemberFormatter {
4559 protected override StringBuilder AppendNamespace (StringBuilder buf, TypeReference type)
4565 class DocTypeFullMemberFormatter : MemberFormatter {
4566 public static readonly MemberFormatter Default = new DocTypeFullMemberFormatter ();
4568 protected override char NestedTypeSeparator {
4573 class DocTypeMemberFormatter : DocTypeFullMemberFormatter {
4574 protected override StringBuilder AppendNamespace (StringBuilder buf, TypeReference type)
4580 class SlashDocMemberFormatter : MemberFormatter {
4582 protected override char[] GenericTypeContainer {
4583 get {return new char[]{'{', '}'};}
4586 private bool AddTypeCount = true;
4588 private TypeReference genDeclType;
4589 private MethodReference genDeclMethod;
4591 protected override StringBuilder AppendTypeName (StringBuilder buf, TypeReference type)
4593 if (type is GenericParameter) {
4595 if (genDeclType != null) {
4596 GenericParameterCollection genArgs = genDeclType.GenericParameters;
4597 for (int i = 0; i < genArgs.Count; ++i) {
4598 if (genArgs [i].Name == type.Name) {
4599 buf.Append ('`').Append (i);
4604 if (genDeclMethod != null) {
4605 GenericParameterCollection genArgs = null;
4606 if (genDeclMethod.IsGenericMethod ()) {
4607 genArgs = genDeclMethod.GenericParameters;
4608 for (int i = 0; i < genArgs.Count; ++i) {
4609 if (genArgs [i].Name == type.Name) {
4610 buf.Append ("``").Append (i);
4616 if (genDeclType == null && genDeclMethod == null) {
4617 // Probably from within an explicitly implemented interface member,
4618 // where CSC uses parameter names instead of indices (why?), e.g.
4619 // MyList`2.Mono#DocTest#Generic#IFoo{A}#Method``1(`0,``0) instead of
4620 // MyList`2.Mono#DocTest#Generic#IFoo{`0}#Method``1(`0,``0).
4621 buf.Append (type.Name);
4623 if (buf.Length == l) {
4624 throw new Exception (string.Format (
4625 "Unable to translate generic parameter {0}; genDeclType={1}, genDeclMethod={2}",
4626 type.Name, genDeclType, genDeclMethod));
4630 base.AppendTypeName (buf, type);
4632 int numArgs = type.GenericParameters.Count;
4633 if (type.DeclaringType != null)
4634 numArgs -= type.GenericParameters.Count;
4636 buf.Append ('`').Append (numArgs);
4643 protected override StringBuilder AppendGenericType (StringBuilder buf, TypeReference type)
4646 base.AppendGenericType (buf, type);
4648 AppendType (buf, type);
4652 private StringBuilder AppendType (StringBuilder buf, TypeReference type)
4654 List<TypeReference> decls = DocUtils.GetDeclaringTypes (type);
4655 bool insertNested = false;
4656 int prevParamCount = 0;
4657 foreach (var decl in decls) {
4659 buf.Append (NestedTypeSeparator);
4660 insertNested = true;
4661 base.AppendTypeName (buf, decl);
4662 int argCount = DocUtils.GetGenericArgumentCount (decl);
4663 int numArgs = argCount - prevParamCount;
4664 prevParamCount = argCount;
4666 buf.Append ('`').Append (numArgs);
4671 public override string GetDeclaration (IMemberReference member)
4673 TypeReference r = member as TypeReference;
4675 return "T:" + GetTypeName (r);
4677 return base.GetDeclaration (member);
4680 protected override string GetConstructorName (MethodReference constructor)
4682 return GetMethodDefinitionName (constructor, "#ctor");
4685 protected override string GetMethodName (MethodReference method)
4688 MethodDefinition methodDef = method as MethodDefinition;
4689 if (methodDef == null || !DocUtils.IsExplicitlyImplemented (methodDef))
4692 TypeReference iface;
4693 MethodReference ifaceMethod;
4694 DocUtils.GetInfoForExplicitlyImplementedMethod (methodDef, out iface, out ifaceMethod);
4695 AddTypeCount = false;
4696 name = GetTypeName (iface) + "." + ifaceMethod.Name;
4697 AddTypeCount = true;
4699 return GetMethodDefinitionName (method, name);
4702 private string GetMethodDefinitionName (MethodReference method, string name)
4704 StringBuilder buf = new StringBuilder ();
4705 buf.Append (GetTypeName (method.DeclaringType));
4707 buf.Append (name.Replace (".", "#"));
4708 if (method.IsGenericMethod ()) {
4709 GenericParameterCollection genArgs = method.GenericParameters;
4710 if (genArgs.Count > 0)
4711 buf.Append ("``").Append (genArgs.Count);
4713 ParameterDefinitionCollection parameters = method.Parameters;
4715 genDeclType = method.DeclaringType;
4716 genDeclMethod = method;
4717 AppendParameters (buf, method.DeclaringType.GenericParameters, parameters);
4721 genDeclMethod = null;
4723 return buf.ToString ();
4726 private StringBuilder AppendParameters (StringBuilder buf, GenericParameterCollection genArgs, ParameterDefinitionCollection parameters)
4728 if (parameters.Count == 0)
4733 AppendParameter (buf, genArgs, parameters [0]);
4734 for (int i = 1; i < parameters.Count; ++i) {
4736 AppendParameter (buf, genArgs, parameters [i]);
4739 return buf.Append (')');
4742 private StringBuilder AppendParameter (StringBuilder buf, GenericParameterCollection genArgs, ParameterDefinition parameter)
4744 AddTypeCount = false;
4745 buf.Append (GetTypeName (parameter.ParameterType));
4746 AddTypeCount = true;
4750 protected override string GetPropertyName (PropertyReference property)
4754 PropertyDefinition propertyDef = property as PropertyDefinition;
4755 MethodDefinition method = null;
4756 if (propertyDef != null)
4757 method = propertyDef.GetMethod ?? propertyDef.SetMethod;
4758 if (method != null && !DocUtils.IsExplicitlyImplemented (method))
4759 name = property.Name;
4761 TypeReference iface;
4762 MethodReference ifaceMethod;
4763 DocUtils.GetInfoForExplicitlyImplementedMethod (method, out iface, out ifaceMethod);
4764 AddTypeCount = false;
4765 name = string.Join ("#", new string[]{
4766 GetTypeName (iface).Replace (".", "#"),
4767 DocUtils.GetMember (property.Name)
4769 AddTypeCount = true;
4772 StringBuilder buf = new StringBuilder ();
4773 buf.Append (GetName (property.DeclaringType));
4776 ParameterDefinitionCollection parameters = property.Parameters;
4777 if (parameters.Count > 0) {
4778 genDeclType = property.DeclaringType;
4780 GenericParameterCollection genArgs = property.DeclaringType.GenericParameters;
4781 AppendParameter (buf, genArgs, parameters [0]);
4782 for (int i = 1; i < parameters.Count; ++i) {
4784 AppendParameter (buf, genArgs, parameters [i]);
4789 return buf.ToString ();
4792 protected override string GetFieldName (FieldReference field)
4794 return string.Format ("{0}.{1}",
4795 GetName (field.DeclaringType), field.Name);
4798 protected override string GetEventName (EventReference e)
4800 return string.Format ("{0}.{1}",
4801 GetName (e.DeclaringType), e.Name);
4804 protected override string GetTypeDeclaration (TypeDefinition type)
4806 string name = GetName (type);
4812 protected override string GetConstructorDeclaration (MethodDefinition constructor)
4814 string name = GetName (constructor);
4820 protected override string GetMethodDeclaration (MethodDefinition method)
4822 string name = GetName (method);
4825 if (method.Name == "op_Implicit" || method.Name == "op_Explicit") {
4826 genDeclType = method.DeclaringType;
4827 genDeclMethod = method;
4828 name += "~" + GetName (method.ReturnType.ReturnType);
4830 genDeclMethod = null;
4835 protected override string GetPropertyDeclaration (PropertyDefinition property)
4837 string name = GetName (property);
4843 protected override string GetFieldDeclaration (FieldDefinition field)
4845 string name = GetName (field);
4851 protected override string GetEventDeclaration (EventDefinition e)
4853 string name = GetName (e);
4860 class FileNameMemberFormatter : SlashDocMemberFormatter {
4861 protected override StringBuilder AppendNamespace (StringBuilder buf, TypeReference type)
4866 protected override char NestedTypeSeparator {