Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/api-doc-tools.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mdoc/Mono.Documentation/MDocUpdater.cs3284
-rw-r--r--mdoc/Mono.Documentation/Updater/DocUtils.cs273
-rw-r--r--mdoc/Mono.Documentation/Updater/DocsNodeInfo.cs105
-rw-r--r--mdoc/Mono.Documentation/Updater/DocumentationEnumerator.cs378
-rw-r--r--mdoc/Mono.Documentation/Updater/DocumentationImporter.cs8
-rw-r--r--mdoc/Mono.Documentation/Updater/DocumentationMember.cs151
-rw-r--r--mdoc/Mono.Documentation/Updater/DynamicParserContext.cs30
-rw-r--r--mdoc/Mono.Documentation/Updater/EcmaDocumentationEnumerator.cs169
-rw-r--r--mdoc/Mono.Documentation/Updater/EcmaDocumentationImporter.cs118
-rw-r--r--mdoc/Mono.Documentation/Updater/Formatters/ApplePlatformEnumFormatter.cs95
-rw-r--r--mdoc/Mono.Documentation/Updater/Formatters/AttributeValueFormatter.cs66
-rw-r--r--mdoc/Mono.Documentation/Updater/Formatters/CSharpFullMemberFormatter.cs659
-rw-r--r--mdoc/Mono.Documentation/Updater/Formatters/CSharpMemberFormatter.cs14
-rw-r--r--mdoc/Mono.Documentation/Updater/Formatters/CSharpNativeTypeMemberFormatter.cs26
-rw-r--r--mdoc/Mono.Documentation/Updater/Formatters/DefaultAttributeValueFormatter.cs13
-rw-r--r--mdoc/Mono.Documentation/Updater/Formatters/DocIdFormatter.cs23
-rw-r--r--mdoc/Mono.Documentation/Updater/Formatters/DocTypeFullMemberFormatter.cs12
-rw-r--r--mdoc/Mono.Documentation/Updater/Formatters/DocTypeMemberFormatter.cs14
-rw-r--r--mdoc/Mono.Documentation/Updater/Formatters/FileNameMemberFormatter.cs19
-rw-r--r--mdoc/Mono.Documentation/Updater/Formatters/ILFullMemberFormatter.cs573
-rw-r--r--mdoc/Mono.Documentation/Updater/Formatters/ILMemberFormatter.cs14
-rw-r--r--mdoc/Mono.Documentation/Updater/Formatters/ILNativeTypeMemberFormatter.cs10
-rw-r--r--mdoc/Mono.Documentation/Updater/Formatters/MemberFormatter.cs421
-rw-r--r--mdoc/Mono.Documentation/Updater/Formatters/SlashDocMemberFormatter.cs321
-rw-r--r--mdoc/Mono.Documentation/Updater/Formatters/StandardFlagsEnumFormatter.cs34
-rw-r--r--mdoc/Mono.Documentation/Updater/Frameworks/AssemblySet.cs (renamed from mdoc/Mono.Documentation/Frameworks/AssemblySet.cs)2
-rw-r--r--mdoc/Mono.Documentation/Updater/Frameworks/FrameworkEntry.cs (renamed from mdoc/Mono.Documentation/Frameworks/FrameworkEntry.cs)2
-rw-r--r--mdoc/Mono.Documentation/Updater/Frameworks/FrameworkIndex.cs (renamed from mdoc/Mono.Documentation/Frameworks/FrameworkIndex.cs)2
-rw-r--r--mdoc/Mono.Documentation/Updater/Frameworks/FrameworkTypeEntry.cs (renamed from mdoc/Mono.Documentation/Frameworks/FrameworkTypeEntry.cs)2
-rw-r--r--mdoc/Mono.Documentation/Updater/Frameworks/UwpResolver.cs (renamed from mdoc/Mono.Documentation/Frameworks/UwpResolver.cs)2
-rw-r--r--mdoc/Mono.Documentation/Updater/MemberFormatterState.cs8
-rw-r--r--mdoc/Mono.Documentation/Updater/MsxdocDocumentationImporter.cs135
-rw-r--r--mdoc/Mono.Documentation/Updater/ResolvedTypeInfo.cs29
-rw-r--r--mdoc/Mono.Documentation/Util/ApiStyle.cs8
-rw-r--r--mdoc/Mono.Documentation/Util/CecilExtensions.cs120
-rw-r--r--mdoc/Mono.Documentation/Util/NativeTypeManager.cs125
-rw-r--r--mdoc/Mono.Documentation/assembler.cs1
-rw-r--r--mdoc/Mono.Documentation/exceptions.cs3
-rw-r--r--mdoc/Mono.Documentation/monodocer.cs6451
-rw-r--r--mdoc/mdoc.Test/FormatterTests.cs2
-rw-r--r--mdoc/mdoc.csproj42
41 files changed, 7301 insertions, 6463 deletions
diff --git a/mdoc/Mono.Documentation/MDocUpdater.cs b/mdoc/Mono.Documentation/MDocUpdater.cs
new file mode 100644
index 00000000..cab63bed
--- /dev/null
+++ b/mdoc/Mono.Documentation/MDocUpdater.cs
@@ -0,0 +1,3284 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Globalization;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Xml;
+using System.Xml.Linq;
+using System.Xml.XPath;
+
+using Mono.Cecil;
+using Mono.Documentation.Updater;
+using Mono.Documentation.Updater.Frameworks;
+using Mono.Documentation.Util;
+using Mono.Options;
+
+using MyXmlNodeList = System.Collections.Generic.List<System.Xml.XmlNode>;
+using StringList = System.Collections.Generic.List<string>;
+using StringToXmlNodeMap = System.Collections.Generic.Dictionary<string, System.Xml.XmlNode>;
+
+namespace Mono.Documentation
+{
+ class MDocUpdater : MDocCommand
+ {
+ string srcPath;
+ List<AssemblySet> assemblies = new List<AssemblySet> ();
+ StringList globalSearchPaths = new StringList ();
+
+ string apistyle = string.Empty;
+ bool isClassicRun;
+
+ bool delete;
+ bool show_exceptions;
+ bool no_assembly_versions, ignore_missing_types;
+ ExceptionLocations? exceptions;
+
+ internal int additions = 0, deletions = 0;
+
+ List<DocumentationImporter> importers = new List<DocumentationImporter> ();
+
+ DocumentationEnumerator docEnum;
+
+ string since;
+
+ static readonly MemberFormatter docTypeFormatter = new DocTypeMemberFormatter ();
+ static readonly MemberFormatter filenameFormatter = new FileNameMemberFormatter ();
+
+ static MemberFormatter[] typeFormatters = new MemberFormatter[]{
+ new CSharpMemberFormatter (),
+ new ILMemberFormatter (),
+ };
+
+ static MemberFormatter[] memberFormatters = new MemberFormatter[]{
+ new CSharpFullMemberFormatter (),
+ new ILFullMemberFormatter (),
+ };
+
+ internal static readonly MemberFormatter slashdocFormatter = new SlashDocMemberFormatter ();
+
+ MyXmlNodeList extensionMethods = new MyXmlNodeList ();
+
+ public static string droppedNamespace = string.Empty;
+
+ public static bool HasDroppedNamespace (TypeDefinition forType)
+ {
+ return HasDroppedNamespace (forType.Module);
+ }
+
+ public static bool HasDroppedNamespace (MemberReference forMember)
+ {
+ return HasDroppedNamespace (forMember.Module);
+ }
+
+ public static bool HasDroppedNamespace (AssemblyDefinition forAssembly)
+ {
+ return HasDroppedNamespace (forAssembly.MainModule);
+ }
+
+ public static bool HasDroppedNamespace (ModuleDefinition forModule)
+ {
+ return !string.IsNullOrWhiteSpace (droppedNamespace) && droppedAssemblies.Any (da => da == forModule.Name);
+ }
+
+ public static bool HasDroppedAnyNamespace ()
+ {
+ return !string.IsNullOrWhiteSpace (droppedNamespace);
+ }
+
+ /// <summary>Logic flag to signify that we should list assemblies at the method level, since there are multiple
+ /// assemblies for a given type/method.</summary>
+ public bool IsMultiAssembly
+ {
+ get
+ {
+ return apistyle == "classic" || apistyle == "unified" || !string.IsNullOrWhiteSpace (FrameworksPath);
+ }
+ }
+
+ /// <summary>Path which contains multiple folders with assemblies. Each folder contained will represent one framework.</summary>
+ string FrameworksPath = string.Empty;
+ FrameworkIndex frameworks;
+ FrameworkIndex frameworksCache;
+
+ static List<string> droppedAssemblies = new List<string> ();
+
+ public string PreserveTag { get; set; }
+ public bool DisableSearchDirectoryRecurse = false;
+ public static MDocUpdater Instance { get; private set; }
+ public static bool SwitchingToMagicTypes { get; private set; }
+
+ public override void Run (IEnumerable<string> args)
+ {
+ Instance = this;
+ show_exceptions = DebugOutput;
+ var types = new List<string> ();
+ var p = new OptionSet () {
+ { "delete",
+ "Delete removed members from the XML files.",
+ v => delete = v != null },
+ { "exceptions:",
+ "Document potential exceptions that members can generate. {SOURCES} " +
+ "is a comma-separated list of:\n" +
+ " asm Method calls in same assembly\n" +
+ " depasm Method calls in dependent assemblies\n" +
+ " all Record all possible exceptions\n" +
+ " added Modifier; only create <exception/>s\n" +
+ " for NEW types/members\n" +
+ "If nothing is specified, then only exceptions from the member will " +
+ "be listed.",
+ v => exceptions = ParseExceptionLocations (v) },
+ { "f=",
+ "Specify a {FLAG} to alter behavior. See later -f* options for available flags.",
+ v => {
+ switch (v) {
+ case "ignore-missing-types":
+ ignore_missing_types = true;
+ break;
+ case "no-assembly-versions":
+ no_assembly_versions = true;
+ break;
+ default:
+ throw new Exception ("Unsupported flag `" + v + "'.");
+ }
+ } },
+ { "fignore-missing-types",
+ "Do not report an error if a --type=TYPE type\nwas not found.",
+ v => ignore_missing_types = v != null },
+ { "fno-assembly-versions",
+ "Do not generate //AssemblyVersion elements.",
+ v => no_assembly_versions = v != null },
+ { "i|import=",
+ "Import documentation from {FILE}.",
+ v => AddImporter (v) },
+ { "L|lib=",
+ "Check for assembly references in {DIRECTORY}.",
+ v => globalSearchPaths.Add (v) },
+ { "library=",
+ "Ignored for compatibility with update-ecma-xml.",
+ v => {} },
+ { "o|out=",
+ "Root {DIRECTORY} to generate/update documentation.",
+ v => srcPath = v },
+ { "r=",
+ "Search for dependent assemblies in the directory containing {ASSEMBLY}.\n" +
+ "(Equivalent to '-L `dirname ASSEMBLY`'.)",
+ v => globalSearchPaths.Add (Path.GetDirectoryName (v)) },
+ { "since=",
+ "Manually specify the assembly {VERSION} that new members were added in.",
+ v => since = v },
+ { "type=",
+ "Only update documentation for {TYPE}.",
+ v => types.Add (v) },
+ { "dropns=",
+ "When processing assembly {ASSEMBLY}, strip off leading namespace {PREFIX}:\n" +
+ " e.g. --dropns ASSEMBLY=PREFIX",
+ v => {
+ var parts = v.Split ('=');
+ if (parts.Length != 2) { Console.Error.WriteLine ("Invalid dropns input"); return; }
+ var assembly = Path.GetFileName (parts [0].Trim ());
+ var prefix = parts [1].Trim();
+ droppedAssemblies.Add (assembly);
+ droppedNamespace = prefix;
+ } },
+ { "ntypes",
+ "If the new assembly is switching to 'magic types', then this switch should be defined.",
+ v => SwitchingToMagicTypes = true },
+ { "preserve",
+ "Do not delete members that don't exist in the assembly, but rather mark them as preserved.",
+ v => PreserveTag = "true" },
+ { "api-style=",
+ "Denotes the apistyle. Currently, only `classic` and `unified` are supported. `classic` set of assemblies should be run first, immediately followed by 'unified' assemblies with the `dropns` parameter.",
+ v => apistyle = v.ToLowerInvariant () },
+ { "fx|frameworks=",
+ "Configuration XML file, that points to directories which contain libraries that span multiple frameworks.",
+ v => FrameworksPath = v },
+ { "use-docid",
+ "Add 'DocId' to the list of type and member signatures",
+ v =>
+ {
+ typeFormatters = typeFormatters.Union (new MemberFormatter[] { new DocIdFormatter () }).ToArray ();
+ memberFormatters = memberFormatters.Union (new MemberFormatter[] { new DocIdFormatter () }).ToArray ();
+ } },
+ { "disable-searchdir-recurse",
+ "Default behavior for adding search directories ('-L') is to recurse them and search in all subdirectories. This disables that",
+ v => DisableSearchDirectoryRecurse = true },
+ };
+ var assemblyPaths = Parse (p, args, "update",
+ "[OPTIONS]+ ASSEMBLIES",
+ "Create or update documentation from ASSEMBLIES.");
+
+ if (!string.IsNullOrWhiteSpace (FrameworksPath))
+ {
+ var configPath = FrameworksPath;
+ var frameworksDir = FrameworksPath;
+ if (!configPath.EndsWith ("frameworks.xml", StringComparison.InvariantCultureIgnoreCase))
+ configPath = Path.Combine (configPath, "frameworks.xml");
+ else
+ frameworksDir = Path.GetDirectoryName (configPath);
+
+ var fxconfig = XDocument.Load (configPath);
+ var fxd = fxconfig.Root
+ .Elements ("Framework")
+ .Select (f => new
+ {
+ Name = f.Attribute ("Name").Value,
+ Path = Path.Combine (frameworksDir, f.Attribute ("Source").Value),
+ SearchPaths = f.Elements ("assemblySearchPath")
+ .Select (a => Path.Combine (frameworksDir, a.Value))
+ .ToArray (),
+ Imports = f.Elements ("import")
+ .Select (a => Path.Combine (frameworksDir, a.Value))
+ .ToArray ()
+ })
+ .Where (f => Directory.Exists (f.Path));
+
+ Func<string, string, IEnumerable<string>> getFiles = (string path, string filters) =>
+ {
+ return filters
+ .Split ('|')
+ .SelectMany (v => Directory.GetFiles (path, v));
+ };
+
+ var sets = fxd.Select (d => new AssemblySet (
+ d.Name,
+ getFiles (d.Path, "*.dll|*.exe|*.winmd"),
+ this.globalSearchPaths.Union (d.SearchPaths),
+ d.Imports
+ ));
+ this.assemblies.AddRange (sets);
+ assemblyPaths.AddRange (sets.SelectMany (s => s.AssemblyPaths));
+
+ // Create a cache of all frameworks, so we can look up
+ // members that may exist only other frameworks before deleting them
+ Console.Write ("Creating frameworks cache: ");
+ FrameworkIndex cacheIndex = new FrameworkIndex (FrameworksPath);
+ string[] prefixesToAvoid = { "get_", "set_", "add_", "remove_", "raise_" };
+ foreach (var assemblySet in this.assemblies)
+ {
+ using (assemblySet)
+ {
+ Console.Write (".");
+ foreach (var assembly in assemblySet.Assemblies)
+ {
+ var a = cacheIndex.StartProcessingAssembly (assembly, assemblySet.Importers);
+ foreach (var type in assembly.GetTypes ())
+ {
+ var t = a.ProcessType (type);
+ foreach (var member in type.GetMembers ().Where (m => !prefixesToAvoid.Any (pre => m.Name.StartsWith (pre, StringComparison.Ordinal))))
+ t.ProcessMember (member);
+ }
+ }
+ }
+ }
+ Console.WriteLine ($"{Environment.NewLine}done caching.");
+ this.frameworksCache = cacheIndex;
+ }
+ else
+ {
+ this.assemblies.Add (new AssemblySet ("Default", assemblyPaths, this.globalSearchPaths, null));
+ }
+
+ if (assemblyPaths == null)
+ return;
+ if (assemblyPaths.Count == 0)
+ Error ("No assemblies specified.");
+
+ if (!DisableSearchDirectoryRecurse)
+ {
+ // unless it's been explicitly disabled, let's
+ // add all of the subdirectories to the resolver
+ // search paths.
+ foreach (var assemblySet in this.assemblies)
+ assemblySet.RecurseSearchDirectories ();
+ }
+
+ // validation for the api-style parameter
+ if (apistyle == "classic")
+ isClassicRun = true;
+ else if (apistyle == "unified")
+ {
+ if (!droppedAssemblies.Any ())
+ Error ("api-style 'unified' must also supply the 'dropns' parameter with at least one assembly and dropped namespace.");
+ }
+ else if (!string.IsNullOrWhiteSpace (apistyle))
+ Error ("api-style '{0}' is not currently supported", apistyle);
+
+ // PARSE BASIC OPTIONS AND LOAD THE ASSEMBLY TO DOCUMENT
+
+ if (srcPath == null)
+ throw new InvalidOperationException ("The --out option is required.");
+
+ docEnum = docEnum ?? new DocumentationEnumerator ();
+
+ // PERFORM THE UPDATES
+ frameworks = new FrameworkIndex (FrameworksPath);
+
+ if (types.Count > 0)
+ {
+ types.Sort ();
+ DoUpdateTypes (srcPath, types, srcPath);
+ }
+ else
+ DoUpdateAssemblies (srcPath, srcPath);
+
+ if (!string.IsNullOrWhiteSpace (FrameworksPath))
+ frameworks.WriteToDisk (srcPath);
+
+ Console.WriteLine ("Members Added: {0}, Members Deleted: {1}", additions, deletions);
+ }
+
+ public static bool IsInAssemblies (string name)
+ {
+ return Instance?.assemblies != null ? Instance.assemblies.Any (a => a.Contains (name)) : true;
+ }
+
+ void AddImporter (string path)
+ {
+ var importer = GetImporter (path, supportsEcmaDoc: true);
+ if (importer != null)
+ importers.Add (importer);
+ }
+
+ internal DocumentationImporter GetImporter (string path, bool supportsEcmaDoc)
+ {
+ try
+ {
+ XmlReader r = new XmlTextReader (path);
+ if (r.Read ())
+ {
+ while (r.NodeType != XmlNodeType.Element)
+ {
+ if (!r.Read ())
+ Error ("Unable to read XML file: {0}.", path);
+ }
+ if (r.LocalName == "doc")
+ {
+ return new MsxdocDocumentationImporter (path);
+ }
+ else if (r.LocalName == "Libraries")
+ {
+ if (!supportsEcmaDoc)
+ throw new NotSupportedException ($"Ecma documentation not supported in this mode: {path}");
+
+ var ecmadocs = new XmlTextReader (path);
+ docEnum = new EcmaDocumentationEnumerator (this, ecmadocs);
+ return new EcmaDocumentationImporter (ecmadocs);
+ }
+ else
+ Error ("Unsupported XML format within {0}.", path);
+ }
+ r.Close ();
+ }
+ catch (Exception e)
+ {
+ Environment.ExitCode = 1;
+ Error ("Could not load XML file: {0}.", e.Message);
+ }
+ return null;
+ }
+
+ static ExceptionLocations ParseExceptionLocations (string s)
+ {
+ ExceptionLocations loc = ExceptionLocations.Member;
+ if (s == null)
+ return loc;
+ foreach (var type in s.Split (','))
+ {
+ switch (type)
+ {
+ case "added": loc |= ExceptionLocations.AddedMembers; break;
+ case "all": loc |= ExceptionLocations.Assembly | ExceptionLocations.DependentAssemblies; break;
+ case "asm": loc |= ExceptionLocations.Assembly; break;
+ case "depasm": loc |= ExceptionLocations.DependentAssemblies; break;
+ default: throw new NotSupportedException ("Unsupported --exceptions value: " + type);
+ }
+ }
+ return loc;
+ }
+
+ internal void Warning (string format, params object[] args)
+ {
+ Message (TraceLevel.Warning, "mdoc: " + format, args);
+ }
+
+ internal AssemblyDefinition LoadAssembly (string name, IAssemblyResolver assemblyResolver)
+ {
+ AssemblyDefinition assembly = null;
+ try
+ {
+ assembly = AssemblyDefinition.ReadAssembly (name, new ReaderParameters { AssemblyResolver = assemblyResolver });
+ }
+ catch (Exception ex)
+ {
+ Warning ($"Unable to load assembly '{name}': {ex.Message}");
+ }
+
+ return assembly;
+ }
+
+ private static void WriteXml (XmlElement element, System.IO.TextWriter output)
+ {
+ OrderTypeAttributes (element);
+ XmlTextWriter writer = new XmlTextWriter (output);
+ writer.Formatting = Formatting.Indented;
+ writer.Indentation = 2;
+ writer.IndentChar = ' ';
+ element.WriteTo (writer);
+ output.WriteLine ();
+ }
+
+ private static void WriteFile (string filename, FileMode mode, Action<TextWriter> action)
+ {
+ Action<string> creator = file =>
+ {
+ using (var writer = OpenWrite (file, mode))
+ action (writer);
+ };
+
+ MdocFile.UpdateFile (filename, creator);
+ }
+
+ private static void OrderTypeAttributes (XmlElement e)
+ {
+ foreach (XmlElement type in e.SelectNodes ("//Type"))
+ {
+ OrderTypeAttributes (type.Attributes);
+ }
+ }
+
+ static readonly string[] TypeAttributeOrder = {
+ "Name", "FullName", "FullNameSP", "Maintainer"
+ };
+
+ private static void OrderTypeAttributes (XmlAttributeCollection c)
+ {
+ XmlAttribute[] attrs = new XmlAttribute[TypeAttributeOrder.Length];
+ for (int i = 0; i < c.Count; ++i)
+ {
+ XmlAttribute a = c[i];
+ for (int j = 0; j < TypeAttributeOrder.Length; ++j)
+ {
+ if (a.Name == TypeAttributeOrder[j])
+ {
+ attrs[j] = a;
+ break;
+ }
+ }
+ }
+ for (int i = attrs.Length - 1; i >= 0; --i)
+ {
+ XmlAttribute n = attrs[i];
+ if (n == null)
+ continue;
+ XmlAttribute r = null;
+ for (int j = i + 1; j < attrs.Length; ++j)
+ {
+ if (attrs[j] != null)
+ {
+ r = attrs[j];
+ break;
+ }
+ }
+ if (r == null)
+ continue;
+ if (c[n.Name] != null)
+ {
+ c.RemoveNamedItem (n.Name);
+ c.InsertBefore (n, r);
+ }
+ }
+ }
+
+ private XmlDocument CreateIndexStub ()
+ {
+ XmlDocument index = new XmlDocument ();
+
+ XmlElement index_root = index.CreateElement ("Overview");
+ index.AppendChild (index_root);
+
+ if (assemblies.Count == 0)
+ throw new Exception ("No assembly");
+
+ XmlElement index_assemblies = index.CreateElement ("Assemblies");
+ index_root.AppendChild (index_assemblies);
+
+ XmlElement index_remarks = index.CreateElement ("Remarks");
+ index_remarks.InnerText = "To be added.";
+ index_root.AppendChild (index_remarks);
+
+ XmlElement index_copyright = index.CreateElement ("Copyright");
+ index_copyright.InnerText = "To be added.";
+ index_root.AppendChild (index_copyright);
+
+ XmlElement index_types = index.CreateElement ("Types");
+ index_root.AppendChild (index_types);
+
+ return index;
+ }
+
+ private static void WriteNamespaceStub (string ns, string outdir)
+ {
+ XmlDocument index = new XmlDocument ();
+
+ XmlElement index_root = index.CreateElement ("Namespace");
+ index.AppendChild (index_root);
+
+ index_root.SetAttribute ("Name", ns);
+
+ XmlElement index_docs = index.CreateElement ("Docs");
+ index_root.AppendChild (index_docs);
+
+ XmlElement index_summary = index.CreateElement ("summary");
+ index_summary.InnerText = "To be added.";
+ index_docs.AppendChild (index_summary);
+
+ XmlElement index_remarks = index.CreateElement ("remarks");
+ index_remarks.InnerText = "To be added.";
+ index_docs.AppendChild (index_remarks);
+
+ WriteFile (outdir + "/ns-" + ns + ".xml", FileMode.CreateNew,
+ writer => WriteXml (index.DocumentElement, writer));
+ }
+
+ public void DoUpdateTypes (string basepath, List<string> typenames, string dest)
+ {
+ var index = CreateIndexForTypes (dest);
+
+ var found = new HashSet<string> ();
+ foreach (var assemblySet in this.assemblies)
+ {
+ using (assemblySet)
+ {
+ foreach (AssemblyDefinition assembly in assemblySet.Assemblies)
+ {
+ var frameworkEntry = frameworks.StartProcessingAssembly (assembly, assemblySet.Importers);
+
+ foreach (TypeDefinition type in docEnum.GetDocumentationTypes (assembly, typenames))
+ {
+ var typeEntry = frameworkEntry.ProcessType (type);
+
+ string relpath = DoUpdateType (type, typeEntry, basepath, dest);
+ if (relpath == null)
+ continue;
+
+ found.Add (type.FullName);
+
+ if (index == null)
+ continue;
+
+ index.Add (assembly);
+ index.Add (type);
+ }
+ }
+ }
+ }
+
+ if (index != null)
+ index.Write ();
+
+ if (ignore_missing_types)
+ return;
+
+ var notFound = from n in typenames where !found.Contains (n) select n;
+ if (notFound.Any ())
+ throw new InvalidOperationException ("Type(s) not found: " + string.Join (", ", notFound.ToArray ()));
+ }
+
+ class IndexForTypes
+ {
+
+ MDocUpdater app;
+ string indexFile;
+
+ XmlDocument index;
+ XmlElement index_types;
+ XmlElement index_assemblies;
+
+ public IndexForTypes (MDocUpdater app, string indexFile, XmlDocument index)
+ {
+ this.app = app;
+ this.indexFile = indexFile;
+ this.index = index;
+
+ index_types = WriteElement (index.DocumentElement, "Types");
+ index_assemblies = WriteElement (index.DocumentElement, "Assemblies");
+ }
+
+ public void Add (AssemblyDefinition assembly)
+ {
+ if (index_assemblies.SelectSingleNode ("Assembly[@Name='" + assembly.Name.Name + "']") != null)
+ return;
+
+ app.AddIndexAssembly (assembly, index_assemblies);
+ }
+
+ public void Add (TypeDefinition type)
+ {
+ app.AddIndexType (type, index_types);
+ }
+
+ public void Write ()
+ {
+ SortIndexEntries (index_types);
+ WriteFile (indexFile, FileMode.Create,
+ writer => WriteXml (index.DocumentElement, writer));
+ }
+ }
+
+ IndexForTypes CreateIndexForTypes (string dest)
+ {
+ string indexFile = Path.Combine (dest, "index.xml");
+ if (File.Exists (indexFile))
+ return null;
+ return new IndexForTypes (this, indexFile, CreateIndexStub ());
+ }
+
+ /// <summary>Constructs the presumed path to the type's documentation file</summary>
+ /// <returns><c>true</c>, if the type file was found, <c>false</c> otherwise.</returns>
+ /// <param name="result">A typle that contains 1) the 'reltypefile', 2) the 'typefile', and 3) the file info</param>
+ bool TryFindTypeFile (string nsname, string typename, string basepath, out Tuple<string, string, FileInfo> result)
+ {
+ string reltypefile = DocUtils.PathCombine (nsname, typename + ".xml");
+ string typefile = Path.Combine (basepath, reltypefile);
+ System.IO.FileInfo file = new System.IO.FileInfo (typefile);
+
+ result = new Tuple<string, string, FileInfo> (reltypefile, typefile, file);
+
+ return file.Exists;
+ }
+
+ public string DoUpdateType (TypeDefinition type, FrameworkTypeEntry typeEntry, string basepath, string dest)
+ {
+ if (type.Namespace == null)
+ Warning ("warning: The type `{0}' is in the root namespace. This may cause problems with display within monodoc.",
+ type.FullName);
+ if (!IsPublic (type))
+ return null;
+
+ // Must get the A+B form of the type name.
+ string typename = GetTypeFileName (type);
+ string nsname = DocUtils.GetNamespace (type);
+
+ // Find the file, if it exists
+ string[] searchLocations = new string[] {
+ nsname
+ };
+
+ if (MDocUpdater.HasDroppedNamespace (type))
+ {
+ // If dropping namespace, types may have moved into a couple of different places.
+ var newSearchLocations = searchLocations.Union (new string[] {
+ string.Format ("{0}.{1}", droppedNamespace, nsname),
+ nsname.Replace (droppedNamespace + ".", string.Empty),
+ MDocUpdater.droppedNamespace
+ });
+
+ searchLocations = newSearchLocations.ToArray ();
+ }
+
+ string reltypefile = "", typefile = "";
+ System.IO.FileInfo file = null;
+
+ foreach (var f in searchLocations)
+ {
+ Tuple<string, string, FileInfo> result;
+ bool fileExists = TryFindTypeFile (f, typename, basepath, out result);
+
+ if (fileExists)
+ {
+ reltypefile = result.Item1;
+ typefile = result.Item2;
+ file = result.Item3;
+
+ break;
+ }
+ }
+
+ if (file == null || !file.Exists)
+ {
+ // we were not able to find a file, let's use the original type informatio.
+ // so that we create the stub in the right place.
+ Tuple<string, string, FileInfo> result;
+ TryFindTypeFile (nsname, typename, basepath, out result);
+
+ reltypefile = result.Item1;
+ typefile = result.Item2;
+ file = result.Item3;
+ }
+
+ string output = null;
+ if (dest == null)
+ {
+ output = typefile;
+ }
+ else if (dest == "-")
+ {
+ output = null;
+ }
+ else
+ {
+ output = Path.Combine (dest, reltypefile);
+ }
+
+ if (file != null && file.Exists)
+ {
+ // Update
+ XmlDocument basefile = new XmlDocument ();
+ try
+ {
+ basefile.Load (typefile);
+ }
+ catch (Exception e)
+ {
+ throw new InvalidOperationException ("Error loading " + typefile + ": " + e.Message, e);
+ }
+
+ DoUpdateType2 ("Updating", basefile, type, typeEntry, output, false);
+ }
+ else
+ {
+ // Stub
+ XmlElement td = StubType (type, output, typeEntry.Framework.Importers);
+ if (td == null)
+ return null;
+ }
+ return reltypefile;
+ }
+
+ private static string GetTypeFileName (TypeReference type)
+ {
+ return filenameFormatter.GetName (type);
+ }
+
+ public static string GetTypeFileName (string typename)
+ {
+ StringBuilder filename = new StringBuilder (typename.Length);
+ int numArgs = 0;
+ int numLt = 0;
+ bool copy = true;
+ for (int i = 0; i < typename.Length; ++i)
+ {
+ char c = typename[i];
+ switch (c)
+ {
+ case '<':
+ copy = false;
+ ++numLt;
+ break;
+ case '>':
+ --numLt;
+ if (numLt == 0)
+ {
+ filename.Append ('`').Append ((numArgs + 1).ToString ());
+ numArgs = 0;
+ copy = true;
+ }
+ break;
+ case ',':
+ if (numLt == 1)
+ ++numArgs;
+ break;
+ default:
+ if (copy)
+ filename.Append (c);
+ break;
+ }
+ }
+ return filename.ToString ();
+ }
+
+ private void AddIndexAssembly (AssemblyDefinition assembly, XmlElement parent)
+ {
+ XmlElement index_assembly = null;
+ if (IsMultiAssembly)
+ index_assembly = (XmlElement)parent.SelectSingleNode ("Assembly[@Name='" + assembly.Name.Name + "']");
+
+ if (index_assembly == null)
+ index_assembly = parent.OwnerDocument.CreateElement ("Assembly");
+
+ index_assembly.SetAttribute ("Name", assembly.Name.Name);
+ index_assembly.SetAttribute ("Version", assembly.Name.Version.ToString ());
+
+ AssemblyNameDefinition name = assembly.Name;
+ if (name.HasPublicKey)
+ {
+ XmlElement pubkey = parent.OwnerDocument.CreateElement ("AssemblyPublicKey");
+ var key = new StringBuilder (name.PublicKey.Length * 3 + 2);
+ key.Append ("[");
+ foreach (byte b in name.PublicKey)
+ key.AppendFormat ("{0,2:x2} ", b);
+ key.Append ("]");
+ pubkey.InnerText = key.ToString ();
+ index_assembly.AppendChild (pubkey);
+ }
+
+ if (!string.IsNullOrEmpty (name.Culture))
+ {
+ XmlElement culture = parent.OwnerDocument.CreateElement ("AssemblyCulture");
+ culture.InnerText = name.Culture;
+ index_assembly.AppendChild (culture);
+ }
+
+ MakeAttributes (index_assembly, GetCustomAttributes (assembly.CustomAttributes, ""));
+ parent.AppendChild (index_assembly);
+ }
+
+ private void AddIndexType (TypeDefinition type, XmlElement index_types)
+ {
+ string typename = GetTypeFileName (type);
+
+ // Add namespace and type nodes into the index file as needed
+ string ns = DocUtils.GetNamespace (type);
+ XmlElement nsnode = (XmlElement)index_types.SelectSingleNode ("Namespace[@Name='" + ns + "']");
+ if (nsnode == null)
+ {
+ nsnode = index_types.OwnerDocument.CreateElement ("Namespace");
+ nsnode.SetAttribute ("Name", ns);
+ index_types.AppendChild (nsnode);
+ }
+ string doc_typename = GetDocTypeName (type);
+ XmlElement typenode = (XmlElement)nsnode.SelectSingleNode ("Type[@Name='" + typename + "']");
+ if (typenode == null)
+ {
+ typenode = index_types.OwnerDocument.CreateElement ("Type");
+ typenode.SetAttribute ("Name", typename);
+ nsnode.AppendChild (typenode);
+ }
+ if (typename != doc_typename)
+ typenode.SetAttribute ("DisplayName", doc_typename);
+ else
+ typenode.RemoveAttribute ("DisplayName");
+
+ typenode.SetAttribute ("Kind", GetTypeKind (type));
+ }
+
+ private void DoUpdateAssemblies (string source, string dest)
+ {
+ string indexfile = dest + "/index.xml";
+ XmlDocument index;
+ if (System.IO.File.Exists (indexfile))
+ {
+ index = new XmlDocument ();
+ index.Load (indexfile);
+
+ // Format change
+ ClearElement (index.DocumentElement, "Assembly");
+ ClearElement (index.DocumentElement, "Attributes");
+ }
+ else
+ {
+ index = CreateIndexStub ();
+ }
+
+ XmlElement index_types = WriteElement (index.DocumentElement, "Types");
+ XmlElement index_assemblies = WriteElement (index.DocumentElement, "Assemblies");
+ if (!IsMultiAssembly)
+ index_assemblies.RemoveAll ();
+
+
+ HashSet<string> goodfiles = new HashSet<string> (StringComparer.OrdinalIgnoreCase);
+
+ int processedAssemblyCount = 0;
+ foreach (var assemblySet in assemblies)
+ {
+ using (assemblySet)
+ {
+ foreach (AssemblyDefinition assm in assemblySet.Assemblies)
+ {
+ AddIndexAssembly (assm, index_assemblies);
+ DoUpdateAssembly (assemblySet, assm, index_types, source, dest, goodfiles);
+ processedAssemblyCount++;
+ }
+ }
+ }
+
+ string defaultTitle = "Untitled";
+ if (processedAssemblyCount == 1)
+ defaultTitle = assemblies[0].Assemblies.First ().Name.Name;
+ WriteElementInitialText (index.DocumentElement, "Title", defaultTitle);
+
+ SortIndexEntries (index_types);
+
+ CleanupFiles (dest, goodfiles);
+ CleanupIndexTypes (index_types, goodfiles);
+ CleanupExtensions (index_types);
+
+ WriteFile (indexfile, FileMode.Create,
+ writer => WriteXml (index.DocumentElement, writer));
+ }
+
+ private static char[] InvalidFilenameChars = { '\\', '/', ':', '*', '?', '"', '<', '>', '|' };
+
+ private void DoUpdateAssembly (AssemblySet assemblySet, AssemblyDefinition assembly, XmlElement index_types, string source, string dest, HashSet<string> goodfiles)
+ {
+ var frameworkEntry = frameworks.StartProcessingAssembly (assembly, assemblySet.Importers);
+
+ foreach (TypeDefinition type in docEnum.GetDocumentationTypes (assembly, null))
+ {
+ string typename = GetTypeFileName (type);
+ if (!IsPublic (type) || typename.IndexOfAny (InvalidFilenameChars) >= 0)
+ continue;
+
+ var typeEntry = frameworkEntry.ProcessType (type);
+
+ string reltypepath = DoUpdateType (type, typeEntry, source, dest);
+ if (reltypepath == null)
+ continue;
+
+ // Add namespace and type nodes into the index file as needed
+ AddIndexType (type, index_types);
+
+ // Ensure the namespace index file exists
+ string namespaceToUse = type.Namespace;
+ if (HasDroppedNamespace (assembly))
+ {
+ namespaceToUse = string.Format ("{0}.{1}", droppedNamespace, namespaceToUse);
+ }
+ string onsdoc = DocUtils.PathCombine (dest, namespaceToUse + ".xml");
+ string nsdoc = DocUtils.PathCombine (dest, "ns-" + namespaceToUse + ".xml");
+ if (File.Exists (onsdoc))
+ {
+ File.Move (onsdoc, nsdoc);
+ }
+
+ if (!File.Exists (nsdoc))
+ {
+ Console.WriteLine ("New Namespace File: " + type.Namespace);
+ WriteNamespaceStub (namespaceToUse, dest);
+ }
+
+ goodfiles.Add (reltypepath);
+ }
+ }
+
+ private static void SortIndexEntries (XmlElement indexTypes)
+ {
+ XmlNodeList namespaces = indexTypes.SelectNodes ("Namespace");
+ XmlNodeComparer c = new AttributeNameComparer ();
+ SortXmlNodes (indexTypes, namespaces, c);
+
+ for (int i = 0; i < namespaces.Count; ++i)
+ SortXmlNodes (namespaces[i], namespaces[i].SelectNodes ("Type"), c);
+ }
+
+ private static void SortXmlNodes (XmlNode parent, XmlNodeList children, XmlNodeComparer comparer)
+ {
+ MyXmlNodeList l = new MyXmlNodeList (children.Count);
+ for (int i = 0; i < children.Count; ++i)
+ l.Add (children[i]);
+ l.Sort (comparer);
+ for (int i = l.Count - 1; i > 0; --i)
+ {
+ parent.InsertBefore (parent.RemoveChild ((XmlNode)l[i - 1]), (XmlNode)l[i]);
+ }
+ }
+
+ abstract class XmlNodeComparer : IComparer, IComparer<XmlNode>
+ {
+ public abstract int Compare (XmlNode x, XmlNode y);
+
+ public int Compare (object x, object y)
+ {
+ return Compare ((XmlNode)x, (XmlNode)y);
+ }
+ }
+
+ class AttributeNameComparer : XmlNodeComparer
+ {
+ string attribute;
+
+ public AttributeNameComparer ()
+ : this ("Name")
+ {
+ }
+
+ public AttributeNameComparer (string attribute)
+ {
+ this.attribute = attribute;
+ }
+
+ public override int Compare (XmlNode x, XmlNode y)
+ {
+ return x.Attributes[attribute].Value.CompareTo (y.Attributes[attribute].Value);
+ }
+ }
+
+ class VersionComparer : XmlNodeComparer
+ {
+ public override int Compare (XmlNode x, XmlNode y)
+ {
+ // Some of the existing docs use e.g. 1.0.x.x, which Version doesn't like.
+ string a = GetVersion (x.InnerText);
+ string b = GetVersion (y.InnerText);
+ return new Version (a).CompareTo (new Version (b));
+ }
+
+ static string GetVersion (string v)
+ {
+ int n = v.IndexOf ("x");
+ if (n < 0)
+ return v;
+ return v.Substring (0, n - 1);
+ }
+ }
+
+ private static string GetTypeKind (TypeDefinition type)
+ {
+ if (type.IsEnum)
+ return "Enumeration";
+ if (type.IsValueType)
+ return "Structure";
+ if (type.IsInterface)
+ return "Interface";
+ if (DocUtils.IsDelegate (type))
+ return "Delegate";
+ if (type.IsClass || type.FullName == "System.Enum") // FIXME
+ return "Class";
+ throw new ArgumentException ("Unknown kind for type: " + type.FullName);
+ }
+
+ public static bool IsPublic (TypeDefinition type)
+ {
+ TypeDefinition decl = type;
+ while (decl != null)
+ {
+ if (!(decl.IsPublic || decl.IsNestedPublic ||
+ decl.IsNestedFamily || decl.IsNestedFamily || decl.IsNestedFamilyOrAssembly))
+ {
+ return false;
+ }
+ decl = (TypeDefinition)decl.DeclaringType;
+ }
+ return true;
+ }
+
+ private void CleanupFiles (string dest, HashSet<string> goodfiles)
+ {
+ // Look for files that no longer correspond to types
+ foreach (System.IO.DirectoryInfo nsdir in new System.IO.DirectoryInfo (dest).GetDirectories ("*").Where (d => Path.GetFileName (d.FullName) != "FrameworksIndex"))
+ {
+ foreach (System.IO.FileInfo typefile in nsdir.GetFiles ("*.xml"))
+ {
+ string relTypeFile = Path.Combine (nsdir.Name, typefile.Name);
+ if (!goodfiles.Contains (relTypeFile))
+ {
+ XmlDocument doc = new XmlDocument ();
+ doc.Load (typefile.FullName);
+ XmlElement e = doc.SelectSingleNode ("/Type") as XmlElement;
+ var assemblyNameNode = doc.SelectSingleNode ("/Type/AssemblyInfo/AssemblyName");
+ if (assemblyNameNode == null)
+ {
+ Warning ("Did not find /Type/AssemblyInfo/AssemblyName on {0}", typefile.FullName);
+ continue;
+ }
+ string assemblyName = assemblyNameNode.InnerText;
+
+
+ Action saveDoc = () =>
+ {
+ using (TextWriter writer = OpenWrite (typefile.FullName, FileMode.Truncate))
+ WriteXml (doc.DocumentElement, writer);
+ };
+
+ if (!IsMultiAssembly)
+ { // only do this for "regular" runs
+ AssemblyDefinition assembly = assemblies
+ .SelectMany (aset => aset.Assemblies)
+ .FirstOrDefault (a => a.Name.Name == assemblyName);
+ if (e != null && !no_assembly_versions && assembly != null && assemblyName != null && UpdateAssemblyVersions (e, assembly, GetAssemblyVersions (assemblyName), false))
+ {
+ saveDoc ();
+ goodfiles.Add (relTypeFile);
+ continue;
+ }
+ }
+
+ Action actuallyDelete = () =>
+ {
+ string newname = typefile.FullName + ".remove";
+ try { System.IO.File.Delete (newname); } catch (Exception) { Warning ("Unable to delete existing file: {0}", newname); }
+ try { typefile.MoveTo (newname); } catch (Exception) { Warning ("Unable to rename to: {0}", newname); }
+ Console.WriteLine ("Class no longer present; file renamed: " + Path.Combine (nsdir.Name, typefile.Name));
+ };
+
+ if (string.IsNullOrWhiteSpace (PreserveTag))
+ { // only do this if there was not a -preserve
+ saveDoc ();
+
+ var unifiedAssemblyNode = doc.SelectSingleNode ("/Type/AssemblyInfo[@apistyle='unified']");
+ var classicAssemblyNode = doc.SelectSingleNode ("/Type/AssemblyInfo[not(@apistyle) or @apistyle='classic']");
+ var unifiedMembers = doc.SelectNodes ("//Member[@apistyle='unified']|//Member/AssemblyInfo[@apistyle='unified']");
+ var classicMembers = doc.SelectNodes ("//Member[@apistyle='classic']|//Member/AssemblyInfo[@apistyle='classic']");
+ bool isUnifiedRun = HasDroppedAnyNamespace ();
+ bool isClassicOrNormalRun = !isUnifiedRun;
+
+ Action<XmlNode, ApiStyle> removeStyles = (x, style) =>
+ {
+ var styledNodes = doc.SelectNodes ("//*[@apistyle='" + style.ToString ().ToLowerInvariant () + "']");
+ if (styledNodes != null && styledNodes.Count > 0)
+ {
+ foreach (var node in styledNodes.Cast<XmlNode> ())
+ {
+ node.ParentNode.RemoveChild (node);
+ }
+ }
+ saveDoc ();
+ };
+ if (isClassicOrNormalRun)
+ {
+ if (unifiedAssemblyNode != null || unifiedMembers.Count > 0)
+ {
+ Warning ("*** this type is marked as unified, not deleting during this run: {0}", typefile.FullName);
+ // if truly removed from both assemblies, it will be removed fully during the unified run
+ removeStyles (doc, ApiStyle.Classic);
+ continue;
+ }
+ else
+ {
+ // we should be safe to delete here because it was not marked as a unified assembly
+ actuallyDelete ();
+ }
+ }
+ if (isUnifiedRun)
+ {
+ if (classicAssemblyNode != null || classicMembers.Count > 0)
+ {
+ Warning ("*** this type is marked as classic, not deleting {0}", typefile.FullName);
+ continue;
+ }
+ else
+ {
+ // safe to delete because it wasn't marked as a classic assembly, so the type is gone in both.
+ actuallyDelete ();
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private static TextWriter OpenWrite (string path, FileMode mode)
+ {
+ var w = new StreamWriter (
+ new FileStream (path, mode),
+ new UTF8Encoding (false)
+ );
+ w.NewLine = "\n";
+ return w;
+ }
+
+ private string[] GetAssemblyVersions (string assemblyName)
+ {
+ return (from a in assemblies.SelectMany (aset => aset.Assemblies)
+ where a.Name.Name == assemblyName
+ select GetAssemblyVersion (a)).ToArray ();
+ }
+
+ private static void CleanupIndexTypes (XmlElement index_types, HashSet<string> goodfiles)
+ {
+ // Look for type nodes that no longer correspond to types
+ MyXmlNodeList remove = new MyXmlNodeList ();
+ foreach (XmlElement typenode in index_types.SelectNodes ("Namespace/Type"))
+ {
+ string fulltypename = Path.Combine (((XmlElement)typenode.ParentNode).GetAttribute ("Name"), typenode.GetAttribute ("Name") + ".xml");
+ if (!goodfiles.Contains (fulltypename))
+ {
+ remove.Add (typenode);
+ }
+ }
+ foreach (XmlNode n in remove)
+ n.ParentNode.RemoveChild (n);
+ }
+
+ private void CleanupExtensions (XmlElement index_types)
+ {
+ XmlNode e = index_types.SelectSingleNode ("/Overview/ExtensionMethods");
+ if (extensionMethods.Count == 0)
+ {
+ if (e == null)
+ return;
+ index_types.SelectSingleNode ("/Overview").RemoveChild (e);
+ return;
+ }
+ if (e == null)
+ {
+ e = index_types.OwnerDocument.CreateElement ("ExtensionMethods");
+ index_types.SelectSingleNode ("/Overview").AppendChild (e);
+ }
+ else
+ e.RemoveAll ();
+ extensionMethods.Sort (DefaultExtensionMethodComparer);
+ foreach (XmlNode m in extensionMethods)
+ {
+ e.AppendChild (index_types.OwnerDocument.ImportNode (m, true));
+ }
+ }
+
+ class ExtensionMethodComparer : XmlNodeComparer
+ {
+ public override int Compare (XmlNode x, XmlNode y)
+ {
+ XmlNode xLink = x.SelectSingleNode ("Member/Link");
+ XmlNode yLink = y.SelectSingleNode ("Member/Link");
+
+ int n = xLink.Attributes["Type"].Value.CompareTo (
+ yLink.Attributes["Type"].Value);
+ if (n != 0)
+ return n;
+ n = xLink.Attributes["Member"].Value.CompareTo (
+ yLink.Attributes["Member"].Value);
+ if (n == 0 && !object.ReferenceEquals (x, y))
+ throw new InvalidOperationException ("Duplicate extension method found!");
+ return n;
+ }
+ }
+
+ static readonly XmlNodeComparer DefaultExtensionMethodComparer = new ExtensionMethodComparer ();
+
+ public void DoUpdateType2 (string message, XmlDocument basefile, TypeDefinition type, FrameworkTypeEntry typeEntry, string output, bool insertSince)
+ {
+ Console.WriteLine (message + ": " + type.FullName);
+
+ StringToXmlNodeMap seenmembers = new StringToXmlNodeMap ();
+
+ // Update type metadata
+ UpdateType (basefile.DocumentElement, type, typeEntry);
+
+ // Update existing members. Delete member nodes that no longer should be there,
+ // and remember what members are already documented so we don't add them again.
+
+ MyXmlNodeList todelete = new MyXmlNodeList ();
+
+ foreach (DocsNodeInfo info in docEnum.GetDocumentationMembers (basefile, type))
+ {
+ XmlElement oldmember = info.Node;
+ MemberReference oldmember2 = info.Member;
+
+ if (info.Member != null && info.Node != null)
+ {
+ // Check for an error condition where the xml MemberName doesn't match the matched member
+ var memberName = GetMemberName (info.Member);
+ var memberAttribute = info.Node.Attributes["MemberName"];
+ if (memberAttribute == null || (memberAttribute.Value != memberName && memberAttribute.Value.Split (',').Length != memberName.Split (',').Length))
+ {
+ oldmember.SetAttribute ("MemberName", memberName);
+ }
+ }
+
+ string sig = oldmember2 != null ? memberFormatters[1].GetDeclaration (oldmember2) : null;
+
+ // Interface implementations and overrides are deleted from the docs
+ // unless the overrides option is given.
+ if (oldmember2 != null && sig == null)
+ oldmember2 = null;
+
+ // Deleted (or signature changed)
+ if (oldmember2 == null)
+ {
+ if (!string.IsNullOrWhiteSpace (FrameworksPath))
+ {
+ // verify that this member wasn't seen in another framework and is indeed valid
+ var sigFromXml = oldmember
+ .GetElementsByTagName ("MemberSignature")
+ .Cast<XmlElement> ()
+ .FirstOrDefault (x => x.GetAttribute ("Language").Equals ("ILAsm"));
+
+ if (sigFromXml != null)
+ {
+ var sigvalue = sigFromXml.GetAttribute ("Value");
+ Func<FrameworkEntry, bool> findTypes = fx =>
+ {
+ var tInstance = fx.Types.FirstOrDefault (t => t.Equals (typeEntry));
+ if (tInstance != null)
+ {
+ return tInstance.ContainsCSharpSig (sigvalue);
+ }
+ return false;
+ };
+ if (frameworksCache.Frameworks.Any (findTypes))
+ continue;
+ }
+ }
+
+ if (!no_assembly_versions && UpdateAssemblyVersions (oldmember, type.Module.Assembly, new string[] { GetAssemblyVersion (type.Module.Assembly) }, false))
+ continue;
+
+ DeleteMember ("Member Removed", output, oldmember, todelete, type);
+ continue;
+ }
+
+ // Duplicated
+ if (seenmembers.ContainsKey (sig))
+ {
+ if (object.ReferenceEquals (oldmember, seenmembers[sig]))
+ {
+ // ignore, already seen
+ }
+ else
+ DeleteMember ("Duplicate Member Found", output, oldmember, todelete, type);
+
+ continue;
+ }
+
+ // Update signature information
+ UpdateMember (info, typeEntry);
+
+ // get all apistyles of sig from info.Node
+ var styles = oldmember.GetElementsByTagName ("MemberSignature").Cast<XmlElement> ()
+ .Where (x => x.GetAttribute ("Language") == "ILAsm" && !seenmembers.ContainsKey (x.GetAttribute ("Value")))
+ .Select (x => x.GetAttribute ("Value"));
+
+
+ typeEntry.ProcessMember (info.Member);
+
+ foreach (var stylesig in styles)
+ {
+ seenmembers.Add (stylesig, oldmember);
+ }
+ }
+ foreach (XmlElement oldmember in todelete)
+ oldmember.ParentNode.RemoveChild (oldmember);
+
+
+ if (!DocUtils.IsDelegate (type))
+ {
+ XmlNode members = WriteElement (basefile.DocumentElement, "Members");
+ var typemembers = type.GetMembers ()
+ .Where (m =>
+ {
+ if (m is TypeDefinition) return false;
+ string cssig = memberFormatters[0].GetDeclaration (m);
+ if (cssig == null) return false;
+ string sig = memberFormatters[1].GetDeclaration (m);
+ if (seenmembers.ContainsKey (sig)) return false;
+
+ // Verify that the member isn't an explicitly implemented
+ // member of an internal interface, in which case we shouldn't return true.
+ MethodDefinition methdef = null;
+ if (m is MethodDefinition)
+ methdef = m as MethodDefinition;
+ else if (m is PropertyDefinition)
+ {
+ var prop = m as PropertyDefinition;
+ methdef = prop.GetMethod ?? prop.SetMethod;
+ }
+
+ if (methdef != null)
+ {
+ TypeReference iface;
+ MethodReference imethod;
+
+ if (methdef.Overrides.Count == 1 && !methdef.IsPublic)
+ {
+ DocUtils.GetInfoForExplicitlyImplementedMethod (methdef, out iface, out imethod);
+ if (!IsPublic (iface.Resolve ())) return false;
+ }
+ }
+
+ return true;
+ })
+ .ToArray ();
+ foreach (MemberReference m in typemembers)
+ {
+ XmlElement mm = MakeMember (basefile, new DocsNodeInfo (null, m), members, typeEntry);
+ if (mm == null) continue;
+
+ if (MDocUpdater.SwitchingToMagicTypes || MDocUpdater.HasDroppedNamespace (m))
+ {
+ // this is a unified style API that obviously doesn't exist in the classic API. Let's mark
+ // it with apistyle="unified", so that it's not displayed for classic style APIs
+ mm.AddApiStyle (ApiStyle.Unified);
+ }
+
+ Console.WriteLine ("Member Added: " + mm.SelectSingleNode ("MemberSignature/@Value").InnerText);
+ additions++;
+ }
+ }
+
+ // Import code snippets from files
+ foreach (XmlNode code in basefile.GetElementsByTagName ("code"))
+ {
+ if (!(code is XmlElement)) continue;
+ string file = ((XmlElement)code).GetAttribute ("src");
+ string lang = ((XmlElement)code).GetAttribute ("lang");
+ if (file != "")
+ {
+ string src = GetCodeSource (lang, Path.Combine (srcPath, file));
+ if (src != null)
+ code.InnerText = src;
+ }
+ }
+
+ if (insertSince && since != null)
+ {
+ XmlNode docs = basefile.DocumentElement.SelectSingleNode ("Docs");
+ docs.AppendChild (CreateSinceNode (basefile));
+ }
+
+ do
+ {
+ XmlElement d = basefile.DocumentElement["Docs"];
+ XmlElement m = basefile.DocumentElement["Members"];
+ if (d != null && m != null)
+ basefile.DocumentElement.InsertBefore (
+ basefile.DocumentElement.RemoveChild (d), m);
+ SortTypeMembers (m);
+ } while (false);
+
+ if (output == null)
+ WriteXml (basefile.DocumentElement, Console.Out);
+ else
+ {
+ FileInfo file = new FileInfo (output);
+ if (!file.Directory.Exists)
+ {
+ Console.WriteLine ("Namespace Directory Created: " + type.Namespace);
+ file.Directory.Create ();
+ }
+ WriteFile (output, FileMode.Create,
+ writer => WriteXml (basefile.DocumentElement, writer));
+ }
+ }
+
+ private string GetCodeSource (string lang, string file)
+ {
+ int anchorStart;
+ if (lang == "C#" && (anchorStart = file.IndexOf (".cs#")) >= 0)
+ {
+ // Grab the specified region
+ string region = "#region " + file.Substring (anchorStart + 4);
+ file = file.Substring (0, anchorStart + 3);
+ try
+ {
+ using (StreamReader reader = new StreamReader (file))
+ {
+ string line;
+ StringBuilder src = new StringBuilder ();
+ int indent = -1;
+ while ((line = reader.ReadLine ()) != null)
+ {
+ if (line.Trim () == region)
+ {
+ indent = line.IndexOf (region);
+ continue;
+ }
+ if (indent >= 0 && line.Trim ().StartsWith ("#endregion"))
+ {
+ break;
+ }
+ if (indent >= 0)
+ src.Append (
+ (line.Length > 0 ? line.Substring (indent) : string.Empty) +
+ "\n");
+ }
+ return src.ToString ();
+ }
+ }
+ catch (Exception e)
+ {
+ Warning ("Could not load <code/> file '{0}' region '{1}': {2}",
+ file, region, show_exceptions ? e.ToString () : e.Message);
+ return null;
+ }
+ }
+ try
+ {
+ using (StreamReader reader = new StreamReader (file))
+ return reader.ReadToEnd ();
+ }
+ catch (Exception e)
+ {
+ Warning ("Could not load <code/> file '" + file + "': " + e.Message);
+ }
+ return null;
+ }
+
+ void DeleteMember (string reason, string output, XmlNode member, MyXmlNodeList todelete, TypeDefinition type)
+ {
+ string format = output != null
+ ? "{0}: File='{1}'; Signature='{4}'"
+ : "{0}: XPath='/Type[@FullName=\"{2}\"]/Members/Member[@MemberName=\"{3}\"]'; Signature='{4}'";
+ string signature = member.SelectSingleNode ("MemberSignature[@Language='C#']/@Value").Value;
+ Warning (format,
+ reason,
+ output,
+ member.OwnerDocument.DocumentElement.GetAttribute ("FullName"),
+ member.Attributes["MemberName"].Value,
+ signature);
+
+ // Identify all of the different states that could affect our decision to delete the member
+ bool shouldPreserve = !string.IsNullOrWhiteSpace (PreserveTag);
+ bool hasContent = MemberDocsHaveUserContent (member);
+ bool shouldDelete = !shouldPreserve && (delete || !hasContent);
+
+ bool unifiedRun = HasDroppedNamespace (type);
+
+ var classicAssemblyInfo = member.SelectSingleNode ("AssemblyInfo[not(@apistyle) or @apistyle='classic']");
+ bool nodeIsClassic = classicAssemblyInfo != null || member.HasApiStyle (ApiStyle.Classic);
+ var unifiedAssemblyInfo = member.SelectSingleNode ("AssemblyInfo[@apistyle='unified']");
+ bool nodeIsUnified = unifiedAssemblyInfo != null || member.HasApiStyle (ApiStyle.Unified);
+
+ Action actuallyDelete = () =>
+ {
+ todelete.Add (member);
+ deletions++;
+ };
+
+ if (!shouldDelete)
+ {
+ // explicitly not deleting
+ string message = shouldPreserve ?
+ "Not deleting '{0}' due to --preserve." :
+ "Not deleting '{0}'; must be enabled with the --delete option";
+ Warning (message, signature);
+ }
+ else if (unifiedRun && nodeIsClassic)
+ {
+ // this is a unified run, and the member doesn't exist, but is marked as being in the classic assembly.
+ member.RemoveApiStyle (ApiStyle.Unified);
+ member.AddApiStyle (ApiStyle.Classic);
+ Warning ("Not removing '{0}' since it's still in the classic assembly.", signature);
+ }
+ else if (unifiedRun && !nodeIsClassic)
+ {
+ // unified run, and the node is not classic, which means it doesn't exist anywhere.
+ actuallyDelete ();
+ }
+ else
+ {
+ if (!isClassicRun || (isClassicRun && !nodeIsClassic && !nodeIsUnified))
+ { // regular codepath (ie. not classic/unified)
+ actuallyDelete ();
+ }
+ else
+ { // this is a classic run
+ Warning ("Removing classic from '{0}' ... will be removed in the unified run if not present there.", signature);
+ member.RemoveApiStyle (ApiStyle.Classic);
+ if (classicAssemblyInfo != null)
+ {
+ member.RemoveChild (classicAssemblyInfo);
+ }
+ }
+ }
+ }
+
+ class MemberComparer : XmlNodeComparer
+ {
+ public override int Compare (XmlNode x, XmlNode y)
+ {
+ int r;
+ string xMemberName = x.Attributes["MemberName"].Value;
+ string yMemberName = y.Attributes["MemberName"].Value;
+
+ // generic methods *end* with '>'
+ // it's possible for explicitly implemented generic interfaces to
+ // contain <...> without being a generic method
+ if ((!xMemberName.EndsWith (">") || !yMemberName.EndsWith (">")) &&
+ (r = xMemberName.CompareTo (yMemberName)) != 0)
+ return r;
+
+ int lt;
+ if ((lt = xMemberName.IndexOf ("<")) >= 0)
+ xMemberName = xMemberName.Substring (0, lt);
+ if ((lt = yMemberName.IndexOf ("<")) >= 0)
+ yMemberName = yMemberName.Substring (0, lt);
+ if ((r = xMemberName.CompareTo (yMemberName)) != 0)
+ return r;
+
+ // Handle MemberGroup sorting
+ var sc = StringComparison.InvariantCultureIgnoreCase;
+ if (x.Name.Equals ("MemberGroup", sc) || y.Name.Equals ("MemberGroup", sc))
+ {
+ if (x.Name.Equals ("MemberGroup", sc) && y.Name.Equals ("Member", sc))
+ return -1;
+ else if (x.Name.Equals ("Member", sc) && y.Name.Equals ("MemberGroup", sc))
+ return 1;
+ else
+ return xMemberName.CompareTo (yMemberName);
+ }
+
+ // if @MemberName matches, then it's either two different types of
+ // members sharing the same name, e.g. field & property, or it's an
+ // overloaded method.
+ // for different type, sort based on MemberType value.
+ r = x.SelectSingleNode ("MemberType").InnerText.CompareTo (
+ y.SelectSingleNode ("MemberType").InnerText);
+ if (r != 0)
+ return r;
+
+ // same type -- must be an overloaded method. Sort based on type
+ // parameter count, then parameter count, then by the parameter
+ // type names.
+ XmlNodeList xTypeParams = x.SelectNodes ("TypeParameters/TypeParameter");
+ XmlNodeList yTypeParams = y.SelectNodes ("TypeParameters/TypeParameter");
+ if (xTypeParams.Count != yTypeParams.Count)
+ return xTypeParams.Count <= yTypeParams.Count ? -1 : 1;
+ for (int i = 0; i < xTypeParams.Count; ++i)
+ {
+ r = xTypeParams[i].Attributes["Name"].Value.CompareTo (
+ yTypeParams[i].Attributes["Name"].Value);
+ if (r != 0)
+ return r;
+ }
+
+ XmlNodeList xParams = x.SelectNodes ("Parameters/Parameter");
+ XmlNodeList yParams = y.SelectNodes ("Parameters/Parameter");
+ if (xParams.Count != yParams.Count)
+ return xParams.Count <= yParams.Count ? -1 : 1;
+ for (int i = 0; i < xParams.Count; ++i)
+ {
+ r = xParams[i].Attributes["Type"].Value.CompareTo (
+ yParams[i].Attributes["Type"].Value);
+ if (r != 0)
+ return r;
+ }
+ // all parameters match, but return value might not match if it was
+ // changed between one version and another.
+ XmlNode xReturn = x.SelectSingleNode ("ReturnValue/ReturnType");
+ XmlNode yReturn = y.SelectSingleNode ("ReturnValue/ReturnType");
+ if (xReturn != null && yReturn != null)
+ {
+ r = xReturn.InnerText.CompareTo (yReturn.InnerText);
+ if (r != 0)
+ return r;
+ }
+
+ return 0;
+ }
+ }
+
+ static readonly MemberComparer DefaultMemberComparer = new MemberComparer ();
+
+ private static void SortTypeMembers (XmlNode members)
+ {
+ if (members == null)
+ return;
+ SortXmlNodes (members, members.SelectNodes ("Member|MemberGroup"), DefaultMemberComparer);
+ }
+
+ private static bool MemberDocsHaveUserContent (XmlNode e)
+ {
+ e = (XmlElement)e.SelectSingleNode ("Docs");
+ if (e == null) return false;
+ foreach (XmlElement d in e.SelectNodes ("*"))
+ if (d.InnerText != "" && !d.InnerText.StartsWith ("To be added"))
+ return true;
+ return false;
+ }
+
+ // UPDATE HELPER FUNCTIONS
+
+ // CREATE A STUB DOCUMENTATION FILE
+
+ public XmlElement StubType (TypeDefinition type, string output, IEnumerable<DocumentationImporter> importers)
+ {
+ string typesig = typeFormatters[0].GetDeclaration (type);
+ if (typesig == null) return null; // not publicly visible
+
+ XmlDocument doc = new XmlDocument ();
+ XmlElement root = doc.CreateElement ("Type");
+ doc.AppendChild (root);
+
+ var frameworkEntry = frameworks.StartProcessingAssembly (type.Module.Assembly, importers);
+ var typeEntry = frameworkEntry.ProcessType (type);
+ DoUpdateType2 ("New Type", doc, type, typeEntry, output, true);
+
+ return root;
+ }
+
+ private XmlElement CreateSinceNode (XmlDocument doc)
+ {
+ XmlElement s = doc.CreateElement ("since");
+ s.SetAttribute ("version", since);
+ return s;
+ }
+
+ // STUBBING/UPDATING FUNCTIONS
+
+ public void UpdateType (XmlElement root, TypeDefinition type, FrameworkTypeEntry typeEntry)
+ {
+ root.SetAttribute ("Name", GetDocTypeName (type));
+ root.SetAttribute ("FullName", GetDocTypeFullName (type));
+
+ foreach (MemberFormatter f in typeFormatters)
+ {
+ string element = "TypeSignature[@Language='" + f.Language + "']";
+ string valueToUse = f.GetDeclaration (type);
+
+ AddXmlNode (
+ root.SelectNodes (element).Cast<XmlElement> ().ToArray (),
+ x => x.GetAttribute ("Value") == valueToUse,
+ x => x.SetAttribute ("Value", valueToUse),
+ () =>
+ {
+ var node = WriteElementAttribute (root, element, "Language", f.Language, forceNewElement: true);
+ var newnode = WriteElementAttribute (root, node, "Value", valueToUse);
+ return newnode;
+ },
+ type);
+ }
+
+ AddAssemblyNameToNode (root, type);
+
+ string assemblyInfoNodeFilter = MDocUpdater.HasDroppedNamespace (type) ? "[@apistyle='unified']" : "[not(@apistyle) or @apistyle='classic']";
+ Func<XmlElement, bool> assemblyFilter = x => x.SelectSingleNode ("AssemblyName").InnerText == type.Module.Assembly.Name.Name;
+ foreach (var ass in root.SelectNodes ("AssemblyInfo" + assemblyInfoNodeFilter).Cast<XmlElement> ().Where (assemblyFilter))
+ {
+ WriteElementText (ass, "AssemblyName", type.Module.Assembly.Name.Name);
+ if (!no_assembly_versions)
+ {
+ UpdateAssemblyVersions (ass, type, true);
+ }
+ else
+ {
+ var versions = ass.SelectNodes ("AssemblyVersion").Cast<XmlNode> ().ToList ();
+ foreach (var version in versions)
+ ass.RemoveChild (version);
+ }
+ if (!string.IsNullOrEmpty (type.Module.Assembly.Name.Culture))
+ WriteElementText (ass, "AssemblyCulture", type.Module.Assembly.Name.Culture);
+ else
+ ClearElement (ass, "AssemblyCulture");
+
+
+ // Why-oh-why do we put assembly attributes in each type file?
+ // Neither monodoc nor monodocs2html use them, so I'm deleting them
+ // since they're outdated in current docs, and a waste of space.
+ //MakeAttributes(ass, type.Assembly, true);
+ XmlNode assattrs = ass.SelectSingleNode ("Attributes");
+ if (assattrs != null)
+ ass.RemoveChild (assattrs);
+
+ NormalizeWhitespace (ass);
+ }
+
+ if (type.IsGenericType ())
+ {
+ MakeTypeParameters (root, type.GenericParameters, type, MDocUpdater.HasDroppedNamespace (type));
+ }
+ else
+ {
+ ClearElement (root, "TypeParameters");
+ }
+
+ if (type.BaseType != null)
+ {
+ XmlElement basenode = WriteElement (root, "Base");
+
+ string basetypename = GetDocTypeFullName (type.BaseType);
+ if (basetypename == "System.MulticastDelegate") basetypename = "System.Delegate";
+
+ if (string.IsNullOrWhiteSpace (FrameworksPath))
+ WriteElementText (root, "Base/BaseTypeName", basetypename);
+ else
+ {
+ // Check for the possibility of an alternate inheritance chain in different frameworks
+ var typeElements = basenode.GetElementsByTagName ("BaseTypeName");
+
+ if (typeElements.Count == 0) // no existing elements, just add
+ WriteElementText (root, "Base/BaseTypeName", basetypename);
+ else
+ {
+ // There's already a BaseTypeName, see if it matches
+ if (typeElements[0].InnerText != basetypename)
+ {
+ // Add a framework alternate if one doesn't already exist
+ var existing = typeElements.Cast<XmlNode> ().Where (n => n.InnerText == basetypename);
+ if (!existing.Any ())
+ {
+ var newNode = WriteElementText (basenode, "BaseTypeName", basetypename, forceNewElement: true);
+ WriteElementAttribute (basenode, newNode, "FrameworkAlternate", typeEntry.Framework.Name);
+ }
+ }
+ }
+ }
+
+ // Document how this type instantiates the generic parameters of its base type
+ TypeReference origBase = type.BaseType.GetElementType ();
+ if (origBase.IsGenericType ())
+ {
+ ClearElement (basenode, "BaseTypeArguments");
+ GenericInstanceType baseInst = type.BaseType as GenericInstanceType;
+ IList<TypeReference> baseGenArgs = baseInst == null ? null : baseInst.GenericArguments;
+ IList<GenericParameter> baseGenParams = origBase.GenericParameters;
+ if (baseGenArgs.Count != baseGenParams.Count)
+ throw new InvalidOperationException ("internal error: number of generic arguments doesn't match number of generic parameters.");
+ for (int i = 0; baseGenArgs != null && i < baseGenArgs.Count; i++)
+ {
+ GenericParameter param = baseGenParams[i];
+ TypeReference value = baseGenArgs[i];
+
+ XmlElement bta = WriteElement (basenode, "BaseTypeArguments");
+ XmlElement arg = bta.OwnerDocument.CreateElement ("BaseTypeArgument");
+ bta.AppendChild (arg);
+ arg.SetAttribute ("TypeParamName", param.Name);
+ arg.InnerText = GetDocTypeFullName (value);
+ }
+ }
+ }
+ else
+ {
+ ClearElement (root, "Base");
+ }
+
+ if (!DocUtils.IsDelegate (type) && !type.IsEnum)
+ {
+ IEnumerable<TypeReference> userInterfaces = DocUtils.GetUserImplementedInterfaces (type);
+ List<string> interface_names = userInterfaces
+ .Select (iface => GetDocTypeFullName (iface))
+ .OrderBy (s => s)
+ .ToList ();
+
+ XmlElement interfaces = WriteElement (root, "Interfaces");
+ interfaces.RemoveAll ();
+ foreach (string iname in interface_names)
+ {
+ XmlElement iface = root.OwnerDocument.CreateElement ("Interface");
+ interfaces.AppendChild (iface);
+ WriteElementText (iface, "InterfaceName", iname);
+ }
+ }
+ else
+ {
+ ClearElement (root, "Interfaces");
+ }
+
+ MakeAttributes (root, GetCustomAttributes (type), type);
+
+ if (DocUtils.IsDelegate (type))
+ {
+ MakeTypeParameters (root, type.GenericParameters, type, MDocUpdater.HasDroppedNamespace (type));
+ var member = type.GetMethod ("Invoke");
+ MakeParameters (root, member, member.Parameters);
+ MakeReturnValue (root, member);
+ }
+
+ DocsNodeInfo typeInfo = new DocsNodeInfo (WriteElement (root, "Docs"), type);
+ MakeDocNode (typeInfo, typeEntry.Framework.Importers);
+
+ if (!DocUtils.IsDelegate (type))
+ WriteElement (root, "Members");
+
+ OrderTypeNodes (root, root.ChildNodes);
+ NormalizeWhitespace (root);
+ }
+
+ /// <summary>Adds an AssemblyInfo with AssemblyName node to an XmlElement.</summary>
+ /// <returns>The assembly that was either added, or was already present</returns>
+ XmlElement AddAssemblyNameToNode (XmlElement root, TypeDefinition type)
+ {
+ return AddAssemblyNameToNode (root, type.Module);
+ }
+
+ /// <summary>Adds an AssemblyInfo with AssemblyName node to an XmlElement.</summary>
+ /// <returns>The assembly that was either added, or was already present</returns>
+ XmlElement AddAssemblyNameToNode (XmlElement root, ModuleDefinition module)
+ {
+ Func<XmlElement, bool> assemblyFilter = x =>
+ {
+ var existingName = x.SelectSingleNode ("AssemblyName");
+
+ bool apiStyleMatches = true;
+ string currentApiStyle = x.GetAttribute ("apistyle");
+ if ((HasDroppedNamespace (module) && !string.IsNullOrWhiteSpace (currentApiStyle) && currentApiStyle != "unified") ||
+ (isClassicRun && (string.IsNullOrWhiteSpace (currentApiStyle) || currentApiStyle != "classic")))
+ {
+ apiStyleMatches = false;
+ }
+ return apiStyleMatches && (existingName == null || (existingName != null && existingName.InnerText == module.Assembly.Name.Name));
+ };
+
+ return AddAssemblyXmlNode (
+ root.SelectNodes ("AssemblyInfo").Cast<XmlElement> ().ToArray (),
+ assemblyFilter, x => WriteElementText (x, "AssemblyName", module.Assembly.Name.Name),
+ () =>
+ {
+ XmlElement ass = WriteElement (root, "AssemblyInfo", forceNewElement: true);
+
+ if (MDocUpdater.HasDroppedNamespace (module))
+ ass.AddApiStyle (ApiStyle.Unified);
+ if (isClassicRun)
+ ass.AddApiStyle (ApiStyle.Classic);
+ return ass;
+ }, module);
+ }
+
+ static readonly string[] TypeNodeOrder = {
+ "TypeSignature",
+ "MemberOfLibrary",
+ "AssemblyInfo",
+ "ThreadingSafetyStatement",
+ "ThreadSafetyStatement",
+ "TypeParameters",
+ "Base",
+ "Interfaces",
+ "Attributes",
+ "Parameters",
+ "ReturnValue",
+ "Docs",
+ "Members",
+ "TypeExcluded",
+ };
+
+ static void OrderTypeNodes (XmlNode member, XmlNodeList children)
+ {
+ ReorderNodes (member, children, TypeNodeOrder);
+ }
+
+ internal static IEnumerable<T> Sort<T> (IEnumerable<T> list)
+ {
+ List<T> l = new List<T> (list);
+ l.Sort ();
+ return l;
+ }
+
+ private void UpdateMember (DocsNodeInfo info, FrameworkTypeEntry typeEntry)
+ {
+ XmlElement me = (XmlElement)info.Node;
+ MemberReference mi = info.Member;
+ typeEntry.ProcessMember (mi);
+ foreach (MemberFormatter f in memberFormatters)
+ {
+ string element = "MemberSignature[@Language='" + f.Language + "']";
+
+ var valueToUse = f.GetDeclaration (mi);
+
+ AddXmlNode (
+ me.SelectNodes (element).Cast<XmlElement> ().ToArray (),
+ x => x.GetAttribute ("Value") == valueToUse,
+ x => x.SetAttribute ("Value", valueToUse),
+ () =>
+ {
+ var node = WriteElementAttribute (me, element, "Language", f.Language, forceNewElement: true);
+ var newNode = WriteElementAttribute (me, node, "Value", valueToUse);
+ return newNode;
+ },
+ mi);
+ }
+
+ WriteElementText (me, "MemberType", GetMemberType (mi));
+
+ if (!no_assembly_versions)
+ {
+ if (!IsMultiAssembly)
+ UpdateAssemblyVersions (me, mi, true);
+ else
+ {
+ var node = AddAssemblyNameToNode (me, mi.Module);
+
+ UpdateAssemblyVersionForAssemblyInfo (node, me, new[] { GetAssemblyVersion (mi.Module.Assembly) }, add: true);
+ }
+ }
+ else
+ {
+ ClearElement (me, "AssemblyInfo");
+ }
+
+ MakeAttributes (me, GetCustomAttributes (mi), mi.DeclaringType);
+
+ MakeReturnValue (me, mi, MDocUpdater.HasDroppedNamespace (mi));
+ if (mi is MethodReference)
+ {
+ MethodReference mb = (MethodReference)mi;
+ if (mb.IsGenericMethod ())
+ MakeTypeParameters (me, mb.GenericParameters, mi, MDocUpdater.HasDroppedNamespace (mi));
+ }
+ MakeParameters (me, mi, MDocUpdater.HasDroppedNamespace (mi));
+
+ string fieldValue;
+ if (mi is FieldDefinition && GetFieldConstValue ((FieldDefinition)mi, out fieldValue))
+ WriteElementText (me, "MemberValue", fieldValue);
+
+ info.Node = WriteElement (me, "Docs");
+ MakeDocNode (info, typeEntry.Framework.Importers);
+ OrderMemberNodes (me, me.ChildNodes);
+ UpdateExtensionMethods (me, info);
+ }
+
+ static void AddXmlNode (XmlElement[] relevant, Func<XmlElement, bool> valueMatches, Action<XmlElement> setValue, Func<XmlElement> makeNewNode, MemberReference member)
+ {
+ AddXmlNode (relevant, valueMatches, setValue, makeNewNode, member.Module);
+ }
+
+ static void AddXmlNode (XmlElement[] relevant, Func<XmlElement, bool> valueMatches, Action<XmlElement> setValue, Func<XmlElement> makeNewNode, TypeDefinition type)
+ {
+ AddXmlNode (relevant, valueMatches, setValue, makeNewNode, type.Module);
+ }
+
+ static XmlElement AddAssemblyXmlNode (XmlElement[] relevant, Func<XmlElement, bool> valueMatches, Action<XmlElement> setValue, Func<XmlElement> makeNewNode, ModuleDefinition module)
+ {
+ bool isUnified = MDocUpdater.HasDroppedNamespace (module);
+ XmlElement thisAssemblyNode = relevant.FirstOrDefault (valueMatches);
+ if (thisAssemblyNode == null)
+ {
+ thisAssemblyNode = makeNewNode ();
+ }
+ setValue (thisAssemblyNode);
+
+ if (isUnified)
+ {
+ thisAssemblyNode.AddApiStyle (ApiStyle.Unified);
+
+ foreach (var otherNodes in relevant.Where (n => n != thisAssemblyNode && n.DoesNotHaveApiStyle (ApiStyle.Unified)))
+ {
+ otherNodes.AddApiStyle (ApiStyle.Classic);
+ }
+ }
+ return thisAssemblyNode;
+ }
+
+ /// <summary>Adds an xml node, reusing the node if it's available</summary>
+ /// <param name="relevant">The existing set of nodes</param>
+ /// <param name="valueMatches">Checks to see if the node's value matches what you're trying to write.</param>
+ /// <param name="setValue">Sets the node's value</param>
+ /// <param name="makeNewNode">Creates a new node, if valueMatches returns false.</param>
+ static void AddXmlNode (XmlElement[] relevant, Func<XmlElement, bool> valueMatches, Action<XmlElement> setValue, Func<XmlElement> makeNewNode, ModuleDefinition module)
+ {
+ bool shouldDuplicate = MDocUpdater.HasDroppedNamespace (module);
+ var styleToUse = shouldDuplicate ? ApiStyle.Unified : ApiStyle.Classic;
+ var existing = relevant;
+ bool done = false;
+ bool addedOldApiStyle = false;
+
+ if (shouldDuplicate)
+ {
+ existing = existing.Where (n => n.HasApiStyle (styleToUse)).ToArray ();
+ foreach (var n in relevant.Where (n => n.DoesNotHaveApiStyle (styleToUse)))
+ {
+ if (valueMatches (n))
+ {
+ done = true;
+ }
+ else
+ {
+ n.AddApiStyle (ApiStyle.Classic);
+ addedOldApiStyle = true;
+ }
+ }
+ }
+ if (!done)
+ {
+ if (!existing.Any ())
+ {
+ var newNode = makeNewNode ();
+ if (shouldDuplicate && addedOldApiStyle)
+ {
+ newNode.AddApiStyle (ApiStyle.Unified);
+ }
+ }
+ else
+ {
+ var itemToReuse = existing.First ();
+ setValue (itemToReuse);
+
+ if (shouldDuplicate && addedOldApiStyle)
+ {
+ itemToReuse.AddApiStyle (styleToUse);
+ }
+ }
+ }
+ }
+
+ static readonly string[] MemberNodeOrder = {
+ "MemberSignature",
+ "MemberType",
+ "AssemblyInfo",
+ "Attributes",
+ "ReturnValue",
+ "TypeParameters",
+ "Parameters",
+ "MemberValue",
+ "Docs",
+ "Excluded",
+ "ExcludedLibrary",
+ "Link",
+ };
+
+ static void OrderMemberNodes (XmlNode member, XmlNodeList children)
+ {
+ ReorderNodes (member, children, MemberNodeOrder);
+ }
+
+ static void ReorderNodes (XmlNode node, XmlNodeList children, string[] ordering)
+ {
+ MyXmlNodeList newChildren = new MyXmlNodeList (children.Count);
+ for (int i = 0; i < ordering.Length; ++i)
+ {
+ for (int j = 0; j < children.Count; ++j)
+ {
+ XmlNode c = children[j];
+ if (c.Name == ordering[i])
+ {
+ newChildren.Add (c);
+ }
+ }
+ }
+ if (newChildren.Count >= 0)
+ node.PrependChild ((XmlNode)newChildren[0]);
+ for (int i = 1; i < newChildren.Count; ++i)
+ {
+ XmlNode prev = (XmlNode)newChildren[i - 1];
+ XmlNode cur = (XmlNode)newChildren[i];
+ node.RemoveChild (cur);
+ node.InsertAfter (cur, prev);
+ }
+ }
+
+ IEnumerable<string> GetCustomAttributes (MemberReference mi)
+ {
+ IEnumerable<string> attrs = Enumerable.Empty<string> ();
+
+ ICustomAttributeProvider p = mi as ICustomAttributeProvider;
+ if (p != null)
+ attrs = attrs.Concat (GetCustomAttributes (p.CustomAttributes, ""));
+
+ PropertyDefinition pd = mi as PropertyDefinition;
+ if (pd != null)
+ {
+ if (pd.GetMethod != null)
+ attrs = attrs.Concat (GetCustomAttributes (pd.GetMethod.CustomAttributes, "get: "));
+ if (pd.SetMethod != null)
+ attrs = attrs.Concat (GetCustomAttributes (pd.SetMethod.CustomAttributes, "set: "));
+ }
+
+ EventDefinition ed = mi as EventDefinition;
+ if (ed != null)
+ {
+ if (ed.AddMethod != null)
+ attrs = attrs.Concat (GetCustomAttributes (ed.AddMethod.CustomAttributes, "add: "));
+ if (ed.RemoveMethod != null)
+ attrs = attrs.Concat (GetCustomAttributes (ed.RemoveMethod.CustomAttributes, "remove: "));
+ }
+
+ return attrs;
+ }
+
+ IEnumerable<string> GetCustomAttributes (IList<CustomAttribute> attributes, string prefix)
+ {
+ foreach (CustomAttribute attribute in attributes.OrderBy (ca => ca.AttributeType.FullName))
+ {
+
+ TypeDefinition attrType = attribute.AttributeType as TypeDefinition;
+ if (attrType != null && !IsPublic (attrType))
+ continue;
+ if (slashdocFormatter.GetName (attribute.AttributeType) == null)
+ continue;
+
+ if (Array.IndexOf (IgnorableAttributes, attribute.AttributeType.FullName) >= 0)
+ continue;
+
+ StringList fields = new StringList ();
+
+ for (int i = 0; i < attribute.ConstructorArguments.Count; ++i)
+ {
+ CustomAttributeArgument argument = attribute.ConstructorArguments[i];
+ fields.Add (MakeAttributesValueString (
+ argument.Value,
+ argument.Type));
+ }
+ var namedArgs =
+ (from namedArg in attribute.Fields
+ select new { Type = namedArg.Argument.Type, Name = namedArg.Name, Value = namedArg.Argument.Value })
+ .Concat (
+ (from namedArg in attribute.Properties
+ select new { Type = namedArg.Argument.Type, Name = namedArg.Name, Value = namedArg.Argument.Value }))
+ .OrderBy (v => v.Name);
+ foreach (var d in namedArgs)
+ fields.Add (string.Format ("{0}={1}", d.Name,
+ MakeAttributesValueString (d.Value, d.Type)));
+
+ string a2 = String.Join (", ", fields.ToArray ());
+ if (a2 != "") a2 = "(" + a2 + ")";
+
+ string name = attribute.GetDeclaringType ();
+ if (name.EndsWith ("Attribute")) name = name.Substring (0, name.Length - "Attribute".Length);
+ yield return prefix + name + a2;
+ }
+ }
+
+ static readonly string[] ValidExtensionMembers = {
+ "Docs",
+ "MemberSignature",
+ "MemberType",
+ "Parameters",
+ "ReturnValue",
+ "TypeParameters",
+ };
+
+ static readonly string[] ValidExtensionDocMembers = {
+ "param",
+ "summary",
+ "typeparam",
+ };
+
+ private void UpdateExtensionMethods (XmlElement e, DocsNodeInfo info)
+ {
+ MethodDefinition me = info.Member as MethodDefinition;
+ if (me == null)
+ return;
+ if (info.Parameters.Count < 1)
+ return;
+ if (!DocUtils.IsExtensionMethod (me))
+ return;
+
+ XmlNode em = e.OwnerDocument.CreateElement ("ExtensionMethod");
+ XmlNode member = e.CloneNode (true);
+ em.AppendChild (member);
+ RemoveExcept (member, ValidExtensionMembers);
+ RemoveExcept (member.SelectSingleNode ("Docs"), ValidExtensionDocMembers);
+ WriteElementText (member, "MemberType", "ExtensionMethod");
+ XmlElement link = member.OwnerDocument.CreateElement ("Link");
+ var linktype = slashdocFormatter.GetName (me.DeclaringType);
+ var linkmember = slashdocFormatter.GetDeclaration (me);
+ link.SetAttribute ("Type", linktype);
+ link.SetAttribute ("Member", linkmember);
+ member.AppendChild (link);
+ AddTargets (em, info);
+
+ if (!IsMultiAssembly || (IsMultiAssembly && !extensionMethods.Any (ex => ex.SelectSingleNode ("Member/Link/@Type").Value == linktype && ex.SelectSingleNode ("Member/Link/@Member").Value == linkmember)))
+ {
+ extensionMethods.Add (em);
+ }
+ }
+
+ private static void RemoveExcept (XmlNode node, string[] except)
+ {
+ if (node == null)
+ return;
+ MyXmlNodeList remove = null;
+ foreach (XmlNode n in node.ChildNodes)
+ {
+ if (Array.BinarySearch (except, n.Name) < 0)
+ {
+ if (remove == null)
+ remove = new MyXmlNodeList ();
+ remove.Add (n);
+ }
+ }
+ if (remove != null)
+ foreach (XmlNode n in remove)
+ node.RemoveChild (n);
+ }
+
+ private static void AddTargets (XmlNode member, DocsNodeInfo info)
+ {
+ XmlElement targets = member.OwnerDocument.CreateElement ("Targets");
+ member.PrependChild (targets);
+ if (!(info.Parameters[0].ParameterType is GenericParameter))
+ {
+ var reference = info.Parameters[0].ParameterType;
+ TypeReference typeReference = reference as TypeReference;
+ var declaration = reference != null ?
+ slashdocFormatter.GetDeclaration (typeReference) :
+ slashdocFormatter.GetDeclaration (reference);
+
+ AppendElementAttributeText (targets, "Target", "Type", declaration);
+ }
+ else
+ {
+ GenericParameter gp = (GenericParameter)info.Parameters[0].ParameterType;
+ IList<TypeReference> constraints = gp.Constraints;
+ if (constraints.Count == 0)
+ AppendElementAttributeText (targets, "Target", "Type", "System.Object");
+ else
+ foreach (TypeReference c in constraints)
+ AppendElementAttributeText (targets, "Target", "Type",
+ slashdocFormatter.GetDeclaration (c));
+ }
+ }
+
+ private static bool GetFieldConstValue (FieldDefinition field, out string value)
+ {
+ value = null;
+ TypeDefinition type = field.DeclaringType.Resolve ();
+ if (type != null && type.IsEnum) return false;
+
+ if (type != null && type.IsGenericType ()) return false;
+ if (!field.HasConstant)
+ return false;
+ if (field.IsLiteral)
+ {
+ object val = field.Constant;
+ if (val == null) value = "null";
+ else if (val is Enum) value = val.ToString ();
+ else if (val is IFormattable)
+ {
+ value = ((IFormattable)val).ToString (null, CultureInfo.InvariantCulture);
+ if (val is string)
+ value = "\"" + value + "\"";
+ }
+ if (value != null && value != "")
+ return true;
+ }
+ return false;
+ }
+
+ // XML HELPER FUNCTIONS
+
+ internal static XmlElement WriteElement (XmlNode parent, string element, bool forceNewElement = false)
+ {
+ XmlElement ret = (XmlElement)parent.SelectSingleNode (element);
+ if (ret == null || forceNewElement)
+ {
+ string[] path = element.Split ('/');
+ foreach (string p in path)
+ {
+ ret = (XmlElement)parent.SelectSingleNode (p);
+ if (ret == null || forceNewElement)
+ {
+ string ename = p;
+ if (ename.IndexOf ('[') >= 0) // strip off XPath predicate
+ ename = ename.Substring (0, ename.IndexOf ('['));
+ ret = parent.OwnerDocument.CreateElement (ename);
+ parent.AppendChild (ret);
+ parent = ret;
+ }
+ else
+ {
+ parent = ret;
+ }
+ }
+ }
+ return ret;
+ }
+ private static XmlElement WriteElementText (XmlNode parent, string element, string value, bool forceNewElement = false)
+ {
+ XmlElement node = WriteElement (parent, element, forceNewElement: forceNewElement);
+ node.InnerText = value;
+ return node;
+ }
+
+ static XmlElement AppendElementText (XmlNode parent, string element, string value)
+ {
+ XmlElement n = parent.OwnerDocument.CreateElement (element);
+ parent.AppendChild (n);
+ n.InnerText = value;
+ return n;
+ }
+
+ static XmlElement AppendElementAttributeText (XmlNode parent, string element, string attribute, string value)
+ {
+ XmlElement n = parent.OwnerDocument.CreateElement (element);
+ parent.AppendChild (n);
+ n.SetAttribute (attribute, value);
+ return n;
+ }
+
+ internal static XmlNode CopyNode (XmlNode source, XmlNode dest)
+ {
+ XmlNode copy = dest.OwnerDocument.ImportNode (source, true);
+ dest.AppendChild (copy);
+ return copy;
+ }
+
+ private static void WriteElementInitialText (XmlElement parent, string element, string value)
+ {
+ XmlElement node = (XmlElement)parent.SelectSingleNode (element);
+ if (node != null)
+ return;
+ node = WriteElement (parent, element);
+ node.InnerText = value;
+ }
+ private static XmlElement WriteElementAttribute (XmlElement parent, string element, string attribute, string value, bool forceNewElement = false)
+ {
+ XmlElement node = WriteElement (parent, element, forceNewElement: forceNewElement);
+ return WriteElementAttribute (parent, node, attribute, value);
+ }
+ private static XmlElement WriteElementAttribute (XmlElement parent, XmlElement node, string attribute, string value)
+ {
+ if (node.GetAttribute (attribute) != value)
+ {
+ node.SetAttribute (attribute, value);
+ }
+ return node;
+ }
+ internal static void ClearElement (XmlElement parent, string name)
+ {
+ XmlElement node = (XmlElement)parent.SelectSingleNode (name);
+ if (node != null)
+ parent.RemoveChild (node);
+ }
+
+ // DOCUMENTATION HELPER FUNCTIONS
+
+ private void MakeDocNode (DocsNodeInfo info, IEnumerable<DocumentationImporter> setimporters)
+ {
+ List<GenericParameter> genericParams = info.GenericParameters;
+ IList<ParameterDefinition> parameters = info.Parameters;
+ TypeReference returntype = info.ReturnType;
+ bool returnisreturn = info.ReturnIsReturn;
+ XmlElement e = info.Node;
+ bool addremarks = info.AddRemarks;
+
+ WriteElementInitialText (e, "summary", "To be added.");
+
+ if (parameters != null)
+ {
+ string[] values = new string[parameters.Count];
+ for (int i = 0; i < values.Length; ++i)
+ values[i] = parameters[i].Name;
+ UpdateParameters (e, "param", values);
+ }
+
+ if (genericParams != null)
+ {
+ string[] values = new string[genericParams.Count];
+ for (int i = 0; i < values.Length; ++i)
+ values[i] = genericParams[i].Name;
+ UpdateParameters (e, "typeparam", values);
+ }
+
+ string retnodename = null;
+ if (returntype != null && returntype.FullName != "System.Void")
+ { // FIXME
+ retnodename = returnisreturn ? "returns" : "value";
+ string retnodename_other = !returnisreturn ? "returns" : "value";
+
+ // If it has a returns node instead of a value node, change its name.
+ XmlElement retother = (XmlElement)e.SelectSingleNode (retnodename_other);
+ if (retother != null)
+ {
+ XmlElement retnode = e.OwnerDocument.CreateElement (retnodename);
+ foreach (XmlNode node in retother)
+ retnode.AppendChild (node.CloneNode (true));
+ e.ReplaceChild (retnode, retother);
+ }
+ else
+ {
+ WriteElementInitialText (e, retnodename, "To be added.");
+ }
+ }
+ else
+ {
+ ClearElement (e, "returns");
+ ClearElement (e, "value");
+ }
+
+ if (addremarks)
+ WriteElementInitialText (e, "remarks", "To be added.");
+
+ if (exceptions.HasValue && info.Member != null &&
+ (exceptions.Value & ExceptionLocations.AddedMembers) == 0)
+ {
+ UpdateExceptions (e, info.Member);
+ }
+
+ foreach (DocumentationImporter importer in importers)
+ {
+ importer.ImportDocumentation (info);
+ }
+ if (setimporters != null)
+ {
+ foreach (var i in setimporters)
+ i.ImportDocumentation (info);
+ }
+
+ OrderDocsNodes (e, e.ChildNodes);
+ NormalizeWhitespace (e);
+ }
+
+ static readonly string[] DocsNodeOrder = {
+ "typeparam", "param", "summary", "returns", "value", "remarks",
+ };
+
+ private static void OrderDocsNodes (XmlNode docs, XmlNodeList children)
+ {
+ ReorderNodes (docs, children, DocsNodeOrder);
+ }
+
+
+ private void UpdateParameters (XmlElement e, string element, string[] values)
+ {
+ if (values != null)
+ {
+ XmlNode[] paramnodes = new XmlNode[values.Length];
+
+ // Some documentation had param nodes with leading spaces.
+ foreach (XmlElement paramnode in e.SelectNodes (element))
+ {
+ paramnode.SetAttribute ("name", paramnode.GetAttribute ("name").Trim ());
+ }
+
+ // If a member has only one parameter, we can track changes to
+ // the name of the parameter easily.
+ if (values.Length == 1 && e.SelectNodes (element).Count == 1)
+ {
+ UpdateParameterName (e, (XmlElement)e.SelectSingleNode (element), values[0]);
+ }
+
+ bool reinsert = false;
+
+ // Pick out existing and still-valid param nodes, and
+ // create nodes for parameters not in the file.
+ Hashtable seenParams = new Hashtable ();
+ for (int pi = 0; pi < values.Length; pi++)
+ {
+ string p = values[pi];
+ seenParams[p] = pi;
+
+ paramnodes[pi] = e.SelectSingleNode (element + "[@name='" + p + "']");
+ if (paramnodes[pi] != null) continue;
+
+ XmlElement pe = e.OwnerDocument.CreateElement (element);
+ pe.SetAttribute ("name", p);
+ pe.InnerText = "To be added.";
+ paramnodes[pi] = pe;
+ reinsert = true;
+ }
+
+ // Remove parameters that no longer exist and check all params are in the right order.
+ int idx = 0;
+ MyXmlNodeList todelete = new MyXmlNodeList ();
+ foreach (XmlElement paramnode in e.SelectNodes (element))
+ {
+ string name = paramnode.GetAttribute ("name");
+ if (!seenParams.ContainsKey (name))
+ {
+ if (!delete && !paramnode.InnerText.StartsWith ("To be added"))
+ {
+ Warning ("The following param node can only be deleted if the --delete option is given: ");
+ if (e.ParentNode == e.OwnerDocument.DocumentElement)
+ {
+ // delegate type
+ Warning ("\tXPath=/Type[@FullName=\"{0}\"]/Docs/param[@name=\"{1}\"]",
+ e.OwnerDocument.DocumentElement.GetAttribute ("FullName"),
+ name);
+ }
+ else
+ {
+ Warning ("\tXPath=/Type[@FullName=\"{0}\"]//Member[@MemberName=\"{1}\"]/Docs/param[@name=\"{2}\"]",
+ e.OwnerDocument.DocumentElement.GetAttribute ("FullName"),
+ e.ParentNode.Attributes["MemberName"].Value,
+ name);
+ }
+ Warning ("\tValue={0}", paramnode.OuterXml);
+ }
+ else
+ {
+ todelete.Add (paramnode);
+ }
+ continue;
+ }
+
+ if ((int)seenParams[name] != idx)
+ reinsert = true;
+
+ idx++;
+ }
+
+ foreach (XmlNode n in todelete)
+ {
+ n.ParentNode.RemoveChild (n);
+ }
+
+ // Re-insert the parameter nodes at the top of the doc section.
+ if (reinsert)
+ for (int pi = values.Length - 1; pi >= 0; pi--)
+ e.PrependChild (paramnodes[pi]);
+ }
+ else
+ {
+ // Clear all existing param nodes
+ foreach (XmlNode paramnode in e.SelectNodes (element))
+ {
+ if (!delete && !paramnode.InnerText.StartsWith ("To be added"))
+ {
+ Console.WriteLine ("The following param node can only be deleted if the --delete option is given:");
+ Console.WriteLine (paramnode.OuterXml);
+ }
+ else
+ {
+ paramnode.ParentNode.RemoveChild (paramnode);
+ }
+ }
+ }
+ }
+
+ private static void UpdateParameterName (XmlElement docs, XmlElement pe, string newName)
+ {
+ string existingName = pe.GetAttribute ("name");
+ pe.SetAttribute ("name", newName);
+ if (existingName == newName)
+ return;
+ foreach (XmlElement paramref in docs.SelectNodes (".//paramref"))
+ if (paramref.GetAttribute ("name").Trim () == existingName)
+ paramref.SetAttribute ("name", newName);
+ }
+
+ class CrefComparer : XmlNodeComparer
+ {
+
+ public CrefComparer ()
+ {
+ }
+
+ public override int Compare (XmlNode x, XmlNode y)
+ {
+ string xType = x.Attributes["cref"].Value;
+ string yType = y.Attributes["cref"].Value;
+ string xNamespace = GetNamespace (xType);
+ string yNamespace = GetNamespace (yType);
+
+ int c = xNamespace.CompareTo (yNamespace);
+ if (c != 0)
+ return c;
+ return xType.CompareTo (yType);
+ }
+
+ static string GetNamespace (string type)
+ {
+ int n = type.LastIndexOf ('.');
+ if (n >= 0)
+ return type.Substring (0, n);
+ return string.Empty;
+ }
+ }
+
+ private void UpdateExceptions (XmlNode docs, MemberReference member)
+ {
+ string indent = new string (' ', 10);
+ foreach (var source in new ExceptionLookup (exceptions.Value)[member])
+ {
+ string cref = slashdocFormatter.GetDeclaration (source.Exception);
+ var node = docs.SelectSingleNode ("exception[@cref='" + cref + "']");
+ if (node != null)
+ continue;
+ XmlElement e = docs.OwnerDocument.CreateElement ("exception");
+ e.SetAttribute ("cref", cref);
+ e.InnerXml = "To be added; from:\n" + indent + "<see cref=\"" +
+ string.Join ("\" />,\n" + indent + "<see cref=\"",
+ source.Sources.Select (m => slashdocFormatter.GetDeclaration (m))
+ .OrderBy (s => s)) +
+ "\" />";
+ docs.AppendChild (e);
+ }
+ SortXmlNodes (docs, docs.SelectNodes ("exception"),
+ new CrefComparer ());
+ }
+
+ private static void NormalizeWhitespace (XmlElement e)
+ {
+ // Remove all text and whitespace nodes from the element so it
+ // is outputted with nice indentation and no blank lines.
+ ArrayList deleteNodes = new ArrayList ();
+ foreach (XmlNode n in e)
+ if (n is XmlText || n is XmlWhitespace || n is XmlSignificantWhitespace)
+ deleteNodes.Add (n);
+ foreach (XmlNode n in deleteNodes)
+ n.ParentNode.RemoveChild (n);
+ }
+
+ private bool UpdateAssemblyVersions (XmlElement root, MemberReference member, bool add)
+ {
+ TypeDefinition type = member as TypeDefinition;
+ if (type == null)
+ type = member.DeclaringType as TypeDefinition;
+
+ var versions = new string[] { GetAssemblyVersion (type.Module.Assembly) };
+
+ if (root.LocalName == "AssemblyInfo")
+ return UpdateAssemblyVersionForAssemblyInfo (root, root.ParentNode as XmlElement, versions, add: true);
+ else
+ return UpdateAssemblyVersions (root, type.Module.Assembly, versions, add);
+ }
+
+ private static string GetAssemblyVersion (AssemblyDefinition assembly)
+ {
+ return assembly.Name.Version.ToString ();
+ }
+
+ private bool UpdateAssemblyVersions (XmlElement root, AssemblyDefinition assembly, string[] assemblyVersions, bool add)
+ {
+ if (IsMultiAssembly)
+ return false;
+
+ XmlElement av = (XmlElement)root.SelectSingleNode ("AssemblyVersions");
+ if (av != null)
+ {
+ // AssemblyVersions is not part of the spec
+ root.RemoveChild (av);
+ }
+
+ string oldNodeFilter = "AssemblyInfo[not(@apistyle) or @apistyle='classic']";
+ string newNodeFilter = "AssemblyInfo[@apistyle='unified']";
+ string thisNodeFilter = MDocUpdater.HasDroppedNamespace (assembly) ? newNodeFilter : oldNodeFilter;
+ string thatNodeFilter = MDocUpdater.HasDroppedNamespace (assembly) ? oldNodeFilter : newNodeFilter;
+
+ XmlElement e = (XmlElement)root.SelectSingleNode (thisNodeFilter);
+ if (e == null)
+ {
+ e = root.OwnerDocument.CreateElement ("AssemblyInfo");
+
+ if (MDocUpdater.HasDroppedNamespace (assembly))
+ {
+ e.AddApiStyle (ApiStyle.Unified);
+ }
+
+ root.AppendChild (e);
+ }
+
+ var thatNode = (XmlElement)root.SelectSingleNode (thatNodeFilter);
+ if (MDocUpdater.HasDroppedNamespace (assembly) && thatNode != null)
+ {
+ // there's a classic node, we should add apistyles
+ e.AddApiStyle (ApiStyle.Unified);
+ thatNode.AddApiStyle (ApiStyle.Classic);
+ }
+
+ return UpdateAssemblyVersionForAssemblyInfo (e, root, assemblyVersions, add);
+ }
+
+ static bool UpdateAssemblyVersionForAssemblyInfo (XmlElement e, XmlElement root, string[] assemblyVersions, bool add)
+ {
+ List<XmlNode> matches = e.SelectNodes ("AssemblyVersion").Cast<XmlNode> ().Where (v => Array.IndexOf (assemblyVersions, v.InnerText) >= 0).ToList ();
+ // matches.Count > 0 && add: ignore -- already present
+ if (matches.Count > 0 && !add)
+ {
+ foreach (XmlNode c in matches)
+ e.RemoveChild (c);
+ }
+ else if (matches.Count == 0 && add)
+ {
+ foreach (string sv in assemblyVersions)
+ {
+ XmlElement c = root.OwnerDocument.CreateElement ("AssemblyVersion");
+ c.InnerText = sv;
+ e.AppendChild (c);
+ }
+ }
+
+ // matches.Count == 0 && !add: ignore -- already not present
+ XmlNodeList avs = e.SelectNodes ("AssemblyVersion");
+ SortXmlNodes (e, avs, new VersionComparer ());
+
+ bool anyNodesLeft = avs.Count != 0;
+ if (!anyNodesLeft)
+ {
+ e.ParentNode.RemoveChild (e);
+ }
+ return anyNodesLeft;
+ }
+
+ // FIXME: get TypeReferences instead of string comparison?
+ private static string[] IgnorableAttributes = {
+ // Security related attributes
+ "System.Reflection.AssemblyKeyFileAttribute",
+ "System.Reflection.AssemblyDelaySignAttribute",
+ // Present in @RefType
+ "System.Runtime.InteropServices.OutAttribute",
+ // For naming the indexer to use when not using indexers
+ "System.Reflection.DefaultMemberAttribute",
+ // for decimal constants
+ "System.Runtime.CompilerServices.DecimalConstantAttribute",
+ // compiler generated code
+ "System.Runtime.CompilerServices.CompilerGeneratedAttribute",
+ // more compiler generated code, e.g. iterator methods
+ "System.Diagnostics.DebuggerHiddenAttribute",
+ "System.Runtime.CompilerServices.FixedBufferAttribute",
+ "System.Runtime.CompilerServices.UnsafeValueTypeAttribute",
+ // extension methods
+ "System.Runtime.CompilerServices.ExtensionAttribute",
+ // Used to differentiate 'object' from C#4 'dynamic'
+ "System.Runtime.CompilerServices.DynamicAttribute",
+ };
+
+ private IEnumerable<char> FilterSpecialChars (string value)
+ {
+ foreach (char c in value)
+ {
+ switch (c)
+ {
+ case '\0':
+ yield return '\\';
+ yield return '0';
+ break;
+ case '\t':
+ yield return '\\';
+ yield return 't';
+ break;
+ case '\n':
+ yield return '\\';
+ yield return 'n';
+ break;
+ case '\r':
+ yield return '\\';
+ yield return 'r';
+ break;
+ case '\f':
+ yield return '\\';
+ yield return 'f';
+ break;
+ case '\b':
+ yield return '\\';
+ yield return 'b';
+ break;
+ default:
+ yield return c;
+ break;
+ }
+ }
+ }
+
+ private void MakeAttributes (XmlElement root, IEnumerable<string> attributes, TypeReference t = null)
+ {
+ if (!attributes.Any ())
+ {
+ ClearElement (root, "Attributes");
+ return;
+ }
+
+ XmlElement e = (XmlElement)root.SelectSingleNode ("Attributes");
+ if (e != null)
+ e.RemoveAll ();
+ else if (e == null)
+ e = root.OwnerDocument.CreateElement ("Attributes");
+
+
+ foreach (string attribute in attributes)
+ {
+ XmlElement ae = root.OwnerDocument.CreateElement ("Attribute");
+ e.AppendChild (ae);
+ var value = new String (FilterSpecialChars (attribute).ToArray ());
+ WriteElementText (ae, "AttributeName", value);
+ }
+
+ if (e.ParentNode == null)
+ root.AppendChild (e);
+
+ NormalizeWhitespace (e);
+ }
+
+ public static string MakeAttributesValueString (object v, TypeReference valueType)
+ {
+ var formatters = new[] {
+ new AttributeValueFormatter (),
+ new ApplePlatformEnumFormatter (),
+ new StandardFlagsEnumFormatter (),
+ new DefaultAttributeValueFormatter (),
+ };
+
+ ResolvedTypeInfo type = new ResolvedTypeInfo (valueType);
+ foreach (var formatter in formatters)
+ {
+ string formattedValue;
+ if (formatter.TryFormatValue (v, type, out formattedValue))
+ {
+ return formattedValue;
+ }
+ }
+
+ // this should never occur because the DefaultAttributeValueFormatter will always
+ // successfully format the value ... but this is needed to satisfy the compiler :)
+ throw new InvalidDataException (string.Format ("Unable to format attribute value ({0})", v.ToString ()));
+ }
+
+ internal static IDictionary<long, string> GetEnumerationValues (TypeDefinition type)
+ {
+ var values = new Dictionary<long, string> ();
+ foreach (var f in
+ (from f in type.Fields
+ where !(f.IsRuntimeSpecialName || f.IsSpecialName)
+ select f))
+ {
+ values[ToInt64 (f.Constant)] = f.Name;
+ }
+ return values;
+ }
+
+ internal static long ToInt64 (object value)
+ {
+ if (value is ulong)
+ return (long)(ulong)value;
+ return Convert.ToInt64 (value);
+ }
+
+ private void MakeParameters (XmlElement root, MemberReference member, IList<ParameterDefinition> parameters, bool shouldDuplicateWithNew = false)
+ {
+ XmlElement e = WriteElement (root, "Parameters");
+
+ int i = 0;
+ foreach (ParameterDefinition p in parameters)
+ {
+ XmlElement pe;
+
+ // param info
+ var ptype = GetDocParameterType (p.ParameterType);
+ var newPType = ptype;
+
+ if (MDocUpdater.SwitchingToMagicTypes)
+ {
+ newPType = NativeTypeManager.ConvertFromNativeType (ptype);
+ }
+
+ // now find the existing node, if it's there so we can reuse it.
+ var nodes = root.SelectSingleNode ("Parameters").SelectNodes ("Parameter")
+ .Cast<XmlElement> ().Where (x => x.GetAttribute ("Name") == p.Name)
+ .ToArray ();
+
+ if (nodes.Count () == 0)
+ {
+ // wasn't found, let's make sure it wasn't just cause the param name was changed
+ nodes = root.SelectSingleNode ("Parameters").SelectNodes ("Parameter")
+ .Cast<XmlElement> ()
+ .Skip (i) // this makes sure we don't inadvertently "reuse" nodes when adding new ones
+ .Where (x => x.GetAttribute ("Name") != p.Name && (x.GetAttribute ("Type") == ptype || x.GetAttribute ("Type") == newPType))
+ .Take (1) // there might be more than one that meets this parameter ... only take the first.
+ .ToArray ();
+ }
+
+ AddXmlNode (nodes,
+ x => x.GetAttribute ("Type") == ptype,
+ x => x.SetAttribute ("Type", ptype),
+ () =>
+ {
+ pe = root.OwnerDocument.CreateElement ("Parameter");
+ e.AppendChild (pe);
+
+ pe.SetAttribute ("Name", p.Name);
+ pe.SetAttribute ("Type", ptype);
+ if (p.ParameterType is ByReferenceType)
+ {
+ if (p.IsOut)
+ pe.SetAttribute ("RefType", "out");
+ else
+ pe.SetAttribute ("RefType", "ref");
+ }
+
+ MakeAttributes (pe, GetCustomAttributes (p.CustomAttributes, ""));
+ return pe;
+ },
+ member);
+
+ i++;
+ }
+ }
+
+ private void MakeTypeParameters (XmlElement root, IList<GenericParameter> typeParams, MemberReference member, bool shouldDuplicateWithNew)
+ {
+ if (typeParams == null || typeParams.Count == 0)
+ {
+ XmlElement f = (XmlElement)root.SelectSingleNode ("TypeParameters");
+ if (f != null)
+ root.RemoveChild (f);
+ return;
+ }
+ XmlElement e = WriteElement (root, "TypeParameters");
+
+ var nodes = e.SelectNodes ("TypeParameter").Cast<XmlElement> ().ToArray ();
+
+ foreach (GenericParameter t in typeParams)
+ {
+
+ IList<TypeReference> constraints = t.Constraints;
+ GenericParameterAttributes attrs = t.Attributes;
+
+
+ AddXmlNode (
+ nodes,
+ x =>
+ {
+ var baseType = e.SelectSingleNode ("BaseTypeName");
+ // TODO: should this comparison take into account BaseTypeName?
+ return x.GetAttribute ("Name") == t.Name;
+ },
+ x => { }, // no additional action required
+ () =>
+ {
+
+ XmlElement pe = root.OwnerDocument.CreateElement ("TypeParameter");
+ e.AppendChild (pe);
+ pe.SetAttribute ("Name", t.Name);
+ MakeAttributes (pe, GetCustomAttributes (t.CustomAttributes, ""), t.DeclaringType);
+ XmlElement ce = (XmlElement)e.SelectSingleNode ("Constraints");
+ if (attrs == GenericParameterAttributes.NonVariant && constraints.Count == 0)
+ {
+ if (ce != null)
+ e.RemoveChild (ce);
+ return pe;
+ }
+ if (ce != null)
+ ce.RemoveAll ();
+ else
+ {
+ ce = root.OwnerDocument.CreateElement ("Constraints");
+ }
+ pe.AppendChild (ce);
+ if ((attrs & GenericParameterAttributes.Contravariant) != 0)
+ AppendElementText (ce, "ParameterAttribute", "Contravariant");
+ if ((attrs & GenericParameterAttributes.Covariant) != 0)
+ AppendElementText (ce, "ParameterAttribute", "Covariant");
+ if ((attrs & GenericParameterAttributes.DefaultConstructorConstraint) != 0)
+ AppendElementText (ce, "ParameterAttribute", "DefaultConstructorConstraint");
+ if ((attrs & GenericParameterAttributes.NotNullableValueTypeConstraint) != 0)
+ AppendElementText (ce, "ParameterAttribute", "NotNullableValueTypeConstraint");
+ if ((attrs & GenericParameterAttributes.ReferenceTypeConstraint) != 0)
+ AppendElementText (ce, "ParameterAttribute", "ReferenceTypeConstraint");
+ foreach (TypeReference c in constraints)
+ {
+ TypeDefinition cd = c.Resolve ();
+ AppendElementText (ce,
+ (cd != null && cd.IsInterface) ? "InterfaceName" : "BaseTypeName",
+ GetDocTypeFullName (c));
+ }
+
+ return pe;
+ },
+ member);
+ }
+ }
+
+ private void MakeParameters (XmlElement root, MemberReference mi, bool shouldDuplicateWithNew)
+ {
+ if (mi is MethodDefinition && ((MethodDefinition)mi).IsConstructor)
+ MakeParameters (root, mi, ((MethodDefinition)mi).Parameters, shouldDuplicateWithNew);
+ else if (mi is MethodDefinition)
+ {
+ MethodDefinition mb = (MethodDefinition)mi;
+ IList<ParameterDefinition> parameters = mb.Parameters;
+ MakeParameters (root, mi, parameters, shouldDuplicateWithNew);
+ if (parameters.Count > 0 && DocUtils.IsExtensionMethod (mb))
+ {
+ XmlElement p = (XmlElement)root.SelectSingleNode ("Parameters/Parameter[position()=1]");
+ p.SetAttribute ("RefType", "this");
+ }
+ }
+ else if (mi is PropertyDefinition)
+ {
+ IList<ParameterDefinition> parameters = ((PropertyDefinition)mi).Parameters;
+ if (parameters.Count > 0)
+ MakeParameters (root, mi, parameters, shouldDuplicateWithNew);
+ else
+ return;
+ }
+ else if (mi is FieldDefinition) return;
+ else if (mi is EventDefinition) return;
+ else throw new ArgumentException ();
+ }
+
+ internal static string GetDocParameterType (TypeReference type)
+ {
+ return GetDocTypeFullName (type).Replace ("@", "&");
+ }
+
+ private void MakeReturnValue (XmlElement root, TypeReference type, IList<CustomAttribute> attributes, bool shouldDuplicateWithNew = false)
+ {
+ XmlElement e = WriteElement (root, "ReturnValue");
+ var valueToUse = GetDocTypeFullName (type);
+
+ AddXmlNode (e.SelectNodes ("ReturnType").Cast<XmlElement> ().ToArray (),
+ x => x.InnerText == valueToUse,
+ x => x.InnerText = valueToUse,
+ () =>
+ {
+ var newNode = WriteElementText (e, "ReturnType", valueToUse, forceNewElement: true);
+ if (attributes != null)
+ MakeAttributes (e, GetCustomAttributes (attributes, ""), type);
+
+ return newNode;
+ },
+ type);
+ }
+
+ private void MakeReturnValue (XmlElement root, MemberReference mi, bool shouldDuplicateWithNew = false)
+ {
+ if (mi is MethodDefinition && ((MethodDefinition)mi).IsConstructor)
+ return;
+ else if (mi is MethodDefinition)
+ MakeReturnValue (root, ((MethodDefinition)mi).ReturnType, ((MethodDefinition)mi).MethodReturnType.CustomAttributes, shouldDuplicateWithNew);
+ else if (mi is PropertyDefinition)
+ MakeReturnValue (root, ((PropertyDefinition)mi).PropertyType, null, shouldDuplicateWithNew);
+ else if (mi is FieldDefinition)
+ MakeReturnValue (root, ((FieldDefinition)mi).FieldType, null, shouldDuplicateWithNew);
+ else if (mi is EventDefinition)
+ MakeReturnValue (root, ((EventDefinition)mi).EventType, null, shouldDuplicateWithNew);
+ else
+ throw new ArgumentException (mi + " is a " + mi.GetType ().FullName);
+ }
+
+ private XmlElement MakeMember (XmlDocument doc, DocsNodeInfo info, XmlNode members, FrameworkTypeEntry typeEntry)
+ {
+ MemberReference mi = info.Member;
+ if (mi is TypeDefinition) return null;
+
+ string sigs = memberFormatters[0].GetDeclaration (mi);
+ if (sigs == null) return null; // not publicly visible
+
+ // no documentation for property/event accessors. Is there a better way of doing this?
+ if (mi.Name.StartsWith ("get_", StringComparison.Ordinal)) return null;
+ if (mi.Name.StartsWith ("set_", StringComparison.Ordinal)) return null;
+ if (mi.Name.StartsWith ("add_", StringComparison.Ordinal)) return null;
+ if (mi.Name.StartsWith ("remove_", StringComparison.Ordinal)) return null;
+ if (mi.Name.StartsWith ("raise_", StringComparison.Ordinal)) return null;
+
+ XmlElement me = doc.CreateElement ("Member");
+ members.AppendChild (me);
+ me.SetAttribute ("MemberName", GetMemberName (mi));
+
+ info.Node = me;
+ UpdateMember (info, typeEntry);
+ if (exceptions.HasValue &&
+ (exceptions.Value & ExceptionLocations.AddedMembers) != 0)
+ UpdateExceptions (info.Node, info.Member);
+
+ if (since != null)
+ {
+ XmlNode docs = me.SelectSingleNode ("Docs");
+ docs.AppendChild (CreateSinceNode (doc));
+ }
+
+ return me;
+ }
+
+ internal static string GetMemberName (MemberReference mi)
+ {
+ MethodDefinition mb = mi as MethodDefinition;
+ if (mb == null)
+ {
+ PropertyDefinition pi = mi as PropertyDefinition;
+ if (pi == null)
+ return mi.Name;
+ return DocUtils.GetPropertyName (pi);
+ }
+ StringBuilder sb = new StringBuilder (mi.Name.Length);
+ if (!DocUtils.IsExplicitlyImplemented (mb))
+ sb.Append (mi.Name);
+ else
+ {
+ TypeReference iface;
+ MethodReference ifaceMethod;
+ DocUtils.GetInfoForExplicitlyImplementedMethod (mb, out iface, out ifaceMethod);
+ sb.Append (GetDocTypeFullName (iface));
+ sb.Append ('.');
+ sb.Append (ifaceMethod.Name);
+ }
+ if (mb.IsGenericMethod ())
+ {
+ IList<GenericParameter> typeParams = mb.GenericParameters;
+ if (typeParams.Count > 0)
+ {
+ sb.Append ("<");
+ sb.Append (typeParams[0].Name);
+ for (int i = 1; i < typeParams.Count; ++i)
+ sb.Append (",").Append (typeParams[i].Name);
+ sb.Append (">");
+ }
+ }
+ return sb.ToString ();
+ }
+
+ /// SIGNATURE GENERATION FUNCTIONS
+ internal static bool IsPrivate (MemberReference mi)
+ {
+ return memberFormatters[0].GetDeclaration (mi) == null;
+ }
+
+ internal static string GetMemberType (MemberReference mi)
+ {
+ if (mi is MethodDefinition && ((MethodDefinition)mi).IsConstructor)
+ return "Constructor";
+ if (mi is MethodDefinition)
+ return "Method";
+ if (mi is PropertyDefinition)
+ return "Property";
+ if (mi is FieldDefinition)
+ return "Field";
+ if (mi is EventDefinition)
+ return "Event";
+ throw new ArgumentException ();
+ }
+
+ private static string GetDocTypeName (TypeReference type)
+ {
+ return docTypeFormatter.GetName (type);
+ }
+
+ internal static string GetDocTypeFullName (TypeReference type)
+ {
+ return DocTypeFullMemberFormatter.Default.GetName (type);
+ }
+
+ internal static string GetXPathForMember (DocumentationMember member)
+ {
+ StringBuilder xpath = new StringBuilder ();
+ xpath.Append ("//Members/Member[@MemberName=\"")
+ .Append (member.MemberName)
+ .Append ("\"]");
+ if (member.Parameters != null && member.Parameters.Count > 0)
+ {
+ xpath.Append ("/Parameters[count(Parameter) = ")
+ .Append (member.Parameters.Count);
+ for (int i = 0; i < member.Parameters.Count; ++i)
+ {
+ xpath.Append (" and Parameter [").Append (i + 1).Append ("]/@Type=\"");
+ xpath.Append (member.Parameters[i]);
+ xpath.Append ("\"");
+ }
+ xpath.Append ("]/..");
+ }
+ return xpath.ToString ();
+ }
+
+ public static string GetXPathForMember (XPathNavigator member)
+ {
+ StringBuilder xpath = new StringBuilder ();
+ xpath.Append ("//Type[@FullName=\"")
+ .Append (member.SelectSingleNode ("../../@FullName").Value)
+ .Append ("\"]/");
+ xpath.Append ("Members/Member[@MemberName=\"")
+ .Append (member.SelectSingleNode ("@MemberName").Value)
+ .Append ("\"]");
+ XPathNodeIterator parameters = member.Select ("Parameters/Parameter");
+ if (parameters.Count > 0)
+ {
+ xpath.Append ("/Parameters[count(Parameter) = ")
+ .Append (parameters.Count);
+ int i = 0;
+ while (parameters.MoveNext ())
+ {
+ ++i;
+ xpath.Append (" and Parameter [").Append (i).Append ("]/@Type=\"");
+ xpath.Append (parameters.Current.Value);
+ xpath.Append ("\"");
+ }
+ xpath.Append ("]/..");
+ }
+ return xpath.ToString ();
+ }
+
+ public static string GetXPathForMember (MemberReference member)
+ {
+ StringBuilder xpath = new StringBuilder ();
+ xpath.Append ("//Type[@FullName=\"")
+ .Append (member.DeclaringType.FullName)
+ .Append ("\"]/");
+ xpath.Append ("Members/Member[@MemberName=\"")
+ .Append (GetMemberName (member))
+ .Append ("\"]");
+
+ IList<ParameterDefinition> parameters = null;
+ if (member is MethodDefinition)
+ parameters = ((MethodDefinition)member).Parameters;
+ else if (member is PropertyDefinition)
+ {
+ parameters = ((PropertyDefinition)member).Parameters;
+ }
+ if (parameters != null && parameters.Count > 0)
+ {
+ xpath.Append ("/Parameters[count(Parameter) = ")
+ .Append (parameters.Count);
+ for (int i = 0; i < parameters.Count; ++i)
+ {
+ xpath.Append (" and Parameter [").Append (i + 1).Append ("]/@Type=\"");
+ xpath.Append (GetDocParameterType (parameters[i].ParameterType));
+ xpath.Append ("\"");
+ }
+ xpath.Append ("]/..");
+ }
+ return xpath.ToString ();
+ }
+ }
+} \ No newline at end of file
diff --git a/mdoc/Mono.Documentation/Updater/DocUtils.cs b/mdoc/Mono.Documentation/Updater/DocUtils.cs
new file mode 100644
index 00000000..cec33ccc
--- /dev/null
+++ b/mdoc/Mono.Documentation/Updater/DocUtils.cs
@@ -0,0 +1,273 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Xml;
+
+using Mono.Cecil;
+
+using Mono.Documentation.Util;
+
+namespace Mono.Documentation.Updater
+{
+ static class DocUtils
+ {
+
+ public static bool DoesNotHaveApiStyle (this XmlElement element, ApiStyle style)
+ {
+ string styleString = style.ToString ().ToLowerInvariant ();
+ string apistylevalue = element.GetAttribute ("apistyle");
+ return apistylevalue != styleString || string.IsNullOrWhiteSpace (apistylevalue);
+ }
+ public static bool HasApiStyle (this XmlElement element, ApiStyle style)
+ {
+ string styleString = style.ToString ().ToLowerInvariant ();
+ return element.GetAttribute ("apistyle") == styleString;
+ }
+ public static bool HasApiStyle (this XmlNode node, ApiStyle style)
+ {
+ var attribute = node.Attributes["apistyle"];
+ return attribute != null && attribute.Value == style.ToString ().ToLowerInvariant ();
+ }
+ public static void AddApiStyle (this XmlElement element, ApiStyle style)
+ {
+ string styleString = style.ToString ().ToLowerInvariant ();
+ var existingValue = element.GetAttribute ("apistyle");
+ if (string.IsNullOrWhiteSpace (existingValue) || existingValue != styleString)
+ {
+ element.SetAttribute ("apistyle", styleString);
+ }
+
+ // Propagate the API style up to the membernode if necessary
+ if (element.LocalName == "AssemblyInfo" && element.ParentNode != null && element.ParentNode.LocalName == "Member")
+ {
+ var member = element.ParentNode;
+ var unifiedAssemblyNode = member.SelectSingleNode ("AssemblyInfo[@apistyle='unified']");
+ var classicAssemblyNode = member.SelectSingleNode ("AssemblyInfo[not(@apistyle) or @apistyle='classic']");
+
+ var parentAttribute = element.ParentNode.Attributes["apistyle"];
+ Action removeStyle = () => element.ParentNode.Attributes.Remove (parentAttribute);
+ Action propagateStyle = () =>
+ {
+ if (parentAttribute == null)
+ {
+ // if it doesn't have the attribute, then add it
+ parentAttribute = element.OwnerDocument.CreateAttribute ("apistyle");
+ parentAttribute.Value = styleString;
+ element.ParentNode.Attributes.Append (parentAttribute);
+ }
+ };
+
+ if ((style == ApiStyle.Classic && unifiedAssemblyNode != null) || (style == ApiStyle.Unified && classicAssemblyNode != null))
+ removeStyle ();
+ else
+ propagateStyle ();
+ }
+ }
+ public static void AddApiStyle (this XmlNode node, ApiStyle style)
+ {
+ string styleString = style.ToString ().ToLowerInvariant ();
+ var existingAttribute = node.Attributes["apistyle"];
+ if (existingAttribute == null)
+ {
+ existingAttribute = node.OwnerDocument.CreateAttribute ("apistyle");
+ node.Attributes.Append (existingAttribute);
+ }
+ existingAttribute.Value = styleString;
+ }
+ public static void RemoveApiStyle (this XmlElement element, ApiStyle style)
+ {
+ string styleString = style.ToString ().ToLowerInvariant ();
+ string existingValue = element.GetAttribute ("apistyle");
+ if (string.IsNullOrWhiteSpace (existingValue) || existingValue == styleString)
+ {
+ element.RemoveAttribute ("apistyle");
+ }
+ }
+ public static void RemoveApiStyle (this XmlNode node, ApiStyle style)
+ {
+ var styleAttribute = node.Attributes["apistyle"];
+ if (styleAttribute != null && styleAttribute.Value == style.ToString ().ToLowerInvariant ())
+ {
+ node.Attributes.Remove (styleAttribute);
+ }
+ }
+
+ public static bool IsExplicitlyImplemented (MethodDefinition method)
+ {
+ return method != null && method.IsPrivate && method.IsFinal && method.IsVirtual;
+ }
+
+ public static string GetTypeDotMember (string name)
+ {
+ int startType, startMethod;
+ startType = startMethod = -1;
+ for (int i = 0; i < name.Length; ++i)
+ {
+ if (name[i] == '.')
+ {
+ startType = startMethod;
+ startMethod = i;
+ }
+ }
+ return name.Substring (startType + 1);
+ }
+
+ public static string GetMember (string name)
+ {
+ int i = name.LastIndexOf ('.');
+ if (i == -1)
+ return name;
+ return name.Substring (i + 1);
+ }
+
+ public static void GetInfoForExplicitlyImplementedMethod (
+ MethodDefinition method, out TypeReference iface, out MethodReference ifaceMethod)
+ {
+ iface = null;
+ ifaceMethod = null;
+ if (method.Overrides.Count != 1)
+ throw new InvalidOperationException ("Could not determine interface type for explicitly-implemented interface member " + method.Name);
+ iface = method.Overrides[0].DeclaringType;
+ ifaceMethod = method.Overrides[0];
+ }
+
+ public static string GetPropertyName (PropertyDefinition pi)
+ {
+ // Issue: (g)mcs-generated assemblies that explicitly implement
+ // properties don't specify the full namespace, just the
+ // TypeName.Property; .NET uses Full.Namespace.TypeName.Property.
+ MethodDefinition method = pi.GetMethod;
+ if (method == null)
+ method = pi.SetMethod;
+ if (!IsExplicitlyImplemented (method))
+ return pi.Name;
+
+ // Need to determine appropriate namespace for this member.
+ TypeReference iface;
+ MethodReference ifaceMethod;
+ GetInfoForExplicitlyImplementedMethod (method, out iface, out ifaceMethod);
+ return string.Join (".", new string[]{
+ DocTypeFullMemberFormatter.Default.GetName (iface),
+ GetMember (pi.Name)});
+ }
+
+ public static string GetNamespace (TypeReference type)
+ {
+ if (type.GetElementType ().IsNested)
+ type = type.GetElementType ();
+ while (type != null && type.IsNested)
+ type = type.DeclaringType;
+ if (type == null)
+ return string.Empty;
+
+ string typeNS = type.Namespace;
+
+ // first, make sure this isn't a type reference to another assembly/module
+
+ bool isInAssembly = MDocUpdater.IsInAssemblies (type.Module.Name);
+ if (isInAssembly && !typeNS.StartsWith ("System") && MDocUpdater.HasDroppedNamespace (type))
+ {
+ typeNS = string.Format ("{0}.{1}", MDocUpdater.droppedNamespace, typeNS);
+ }
+ return typeNS;
+ }
+
+ public static string PathCombine (string dir, string path)
+ {
+ if (dir == null)
+ dir = "";
+ if (path == null)
+ path = "";
+ return Path.Combine (dir, path);
+ }
+
+ public static bool IsExtensionMethod (MethodDefinition method)
+ {
+ return
+ method.CustomAttributes
+ .Any (m => m.AttributeType.FullName == "System.Runtime.CompilerServices.ExtensionAttribute")
+ && method.DeclaringType.CustomAttributes
+ .Any (m => m.AttributeType.FullName == "System.Runtime.CompilerServices.ExtensionAttribute");
+ }
+
+ public static bool IsDelegate (TypeDefinition type)
+ {
+ TypeReference baseRef = type.BaseType;
+ if (baseRef == null)
+ return false;
+ return !type.IsAbstract && baseRef.FullName == "System.Delegate" || // FIXME
+ baseRef.FullName == "System.MulticastDelegate";
+ }
+
+ public static List<TypeReference> GetDeclaringTypes (TypeReference type)
+ {
+ List<TypeReference> decls = new List<TypeReference> ();
+ decls.Add (type);
+ while (type.DeclaringType != null)
+ {
+ decls.Add (type.DeclaringType);
+ type = type.DeclaringType;
+ }
+ decls.Reverse ();
+ return decls;
+ }
+
+ public static int GetGenericArgumentCount (TypeReference type)
+ {
+ GenericInstanceType inst = type as GenericInstanceType;
+ return inst != null
+ ? inst.GenericArguments.Count
+ : type.GenericParameters.Count;
+ }
+
+ public static IEnumerable<TypeReference> GetUserImplementedInterfaces (TypeDefinition type)
+ {
+ HashSet<string> inheritedInterfaces = GetInheritedInterfaces (type);
+ List<TypeReference> userInterfaces = new List<TypeReference> ();
+ foreach (var ii in type.Interfaces)
+ {
+ var iface = ii.InterfaceType;
+ TypeReference lookup = iface.Resolve () ?? iface;
+ if (!inheritedInterfaces.Contains (GetQualifiedTypeName (lookup)))
+ userInterfaces.Add (iface);
+ }
+ return userInterfaces.Where (i => MDocUpdater.IsPublic (i.Resolve ()));
+ }
+
+ private static string GetQualifiedTypeName (TypeReference type)
+ {
+ return "[" + type.Scope.Name + "]" + type.FullName;
+ }
+
+ private static HashSet<string> GetInheritedInterfaces (TypeDefinition type)
+ {
+ HashSet<string> inheritedInterfaces = new HashSet<string> ();
+ Action<TypeDefinition> a = null;
+ a = t =>
+ {
+ if (t == null) return;
+ foreach (var r in t.Interfaces)
+ {
+ inheritedInterfaces.Add (GetQualifiedTypeName (r.InterfaceType));
+ a (r.InterfaceType.Resolve ());
+ }
+ };
+ TypeReference baseRef = type.BaseType;
+ while (baseRef != null)
+ {
+ TypeDefinition baseDef = baseRef.Resolve ();
+ if (baseDef != null)
+ {
+ a (baseDef);
+ baseRef = baseDef.BaseType;
+ }
+ else
+ baseRef = null;
+ }
+ foreach (var r in type.Interfaces)
+ a (r.InterfaceType.Resolve ());
+ return inheritedInterfaces;
+ }
+ }
+} \ No newline at end of file
diff --git a/mdoc/Mono.Documentation/Updater/DocsNodeInfo.cs b/mdoc/Mono.Documentation/Updater/DocsNodeInfo.cs
new file mode 100644
index 00000000..d262fc84
--- /dev/null
+++ b/mdoc/Mono.Documentation/Updater/DocsNodeInfo.cs
@@ -0,0 +1,105 @@
+using System;
+using System.Collections.Generic;
+using System.Xml;
+
+using Mono.Cecil;
+
+using Mono.Documentation.Util;
+
+namespace Mono.Documentation.Updater
+{
+ class DocsNodeInfo
+ {
+ public DocsNodeInfo (XmlElement node)
+ {
+ this.Node = node;
+ }
+
+ public DocsNodeInfo (XmlElement node, TypeDefinition type)
+ : this (node)
+ {
+ SetType (type);
+ }
+
+ public DocsNodeInfo (XmlElement node, MemberReference member)
+ : this (node)
+ {
+ SetMemberInfo (member);
+ }
+
+ void SetType (TypeDefinition type)
+ {
+ if (type == null)
+ throw new ArgumentNullException ("type");
+ Type = type;
+ GenericParameters = new List<GenericParameter> (type.GenericParameters);
+ List<TypeReference> declTypes = DocUtils.GetDeclaringTypes (type);
+ int maxGenArgs = DocUtils.GetGenericArgumentCount (type);
+ for (int i = 0; i < declTypes.Count - 1; ++i)
+ {
+ int remove = System.Math.Min (maxGenArgs,
+ DocUtils.GetGenericArgumentCount (declTypes[i]));
+ maxGenArgs -= remove;
+ while (remove-- > 0)
+ GenericParameters.RemoveAt (0);
+ }
+ if (DocUtils.IsDelegate (type))
+ {
+ Parameters = type.GetMethod ("Invoke").Parameters;
+ ReturnType = type.GetMethod ("Invoke").ReturnType;
+ ReturnIsReturn = true;
+ }
+ }
+
+ void SetMemberInfo (MemberReference member)
+ {
+ if (member == null)
+ throw new ArgumentNullException ("member");
+ ReturnIsReturn = true;
+ AddRemarks = true;
+ Member = member;
+
+ if (member is MethodReference)
+ {
+ MethodReference mr = (MethodReference)member;
+ Parameters = mr.Parameters;
+ if (mr.IsGenericMethod ())
+ {
+ GenericParameters = new List<GenericParameter> (mr.GenericParameters);
+ }
+ }
+ else if (member is PropertyDefinition)
+ {
+ Parameters = ((PropertyDefinition)member).Parameters;
+ }
+
+ if (member is MethodDefinition)
+ {
+ ReturnType = ((MethodDefinition)member).ReturnType;
+ }
+ else if (member is PropertyDefinition)
+ {
+ ReturnType = ((PropertyDefinition)member).PropertyType;
+ ReturnIsReturn = false;
+ }
+
+ // no remarks section for enum members
+ if (member.DeclaringType != null && ((TypeDefinition)member.DeclaringType).IsEnum)
+ AddRemarks = false;
+ }
+
+ public TypeReference ReturnType;
+ public List<GenericParameter> GenericParameters;
+ public IList<ParameterDefinition> Parameters;
+ public bool ReturnIsReturn;
+ public XmlElement Node;
+ public bool AddRemarks = true;
+ public MemberReference Member;
+ public TypeDefinition Type;
+
+ public override string ToString ()
+ {
+ return string.Format ("{0} - {1} - {2}", Type, Member, Node == null ? "no xml" : "with xml");
+ }
+ }
+} \ No newline at end of file
diff --git a/mdoc/Mono.Documentation/Updater/DocumentationEnumerator.cs b/mdoc/Mono.Documentation/Updater/DocumentationEnumerator.cs
new file mode 100644
index 00000000..53d5e8b0
--- /dev/null
+++ b/mdoc/Mono.Documentation/Updater/DocumentationEnumerator.cs
@@ -0,0 +1,378 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Xml;
+
+using Mono.Cecil;
+using StringList = System.Collections.Generic.List<string>;
+
+using Mono.Documentation.Util;
+
+namespace Mono.Documentation.Updater
+{
+ class DocumentationEnumerator
+ {
+
+ public virtual IEnumerable<TypeDefinition> GetDocumentationTypes (AssemblyDefinition assembly, List<string> forTypes)
+ {
+ return GetDocumentationTypes (assembly, forTypes, null);
+ }
+
+ protected IEnumerable<TypeDefinition> GetDocumentationTypes (AssemblyDefinition assembly, List<string> forTypes, HashSet<string> seen)
+ {
+ foreach (TypeDefinition type in assembly.GetTypes ())
+ {
+ if (forTypes != null && forTypes.BinarySearch (type.FullName) < 0)
+ continue;
+ if (seen != null && seen.Contains (type.FullName))
+ continue;
+ yield return type;
+ foreach (TypeDefinition nested in type.NestedTypes)
+ yield return nested;
+ }
+ }
+
+ public virtual IEnumerable<DocsNodeInfo> GetDocumentationMembers (XmlDocument basefile, TypeDefinition type)
+ {
+ foreach (XmlElement oldmember in basefile.SelectNodes ("Type/Members/Member"))
+ {
+ if (oldmember.GetAttribute ("__monodocer-seen__") == "true")
+ {
+ oldmember.RemoveAttribute ("__monodocer-seen__");
+ continue;
+ }
+ MemberReference m = GetMember (type, new DocumentationMember (oldmember));
+ if (m == null)
+ {
+ yield return new DocsNodeInfo (oldmember);
+ }
+ else
+ {
+ yield return new DocsNodeInfo (oldmember, m);
+ }
+ }
+ }
+
+ protected static MemberReference GetMember (TypeDefinition type, DocumentationMember member)
+ {
+ string membertype = member.MemberType;
+
+ string returntype = member.ReturnType;
+
+ string docName = member.MemberName;
+
+ string[] docTypeParams = GetTypeParameters (docName, member.TypeParameters);
+
+ // If we're using 'magic types', then we might get false positives ... in those cases, we keep searching
+ MemberReference likelyCandidate = null;
+
+ // Loop through all members in this type with the same name
+ var reflectedMembers = GetReflectionMembers (type, docName).ToArray ();
+ foreach (MemberReference mi in reflectedMembers)
+ {
+ bool matchedMagicType = false;
+ if (mi is TypeDefinition) continue;
+ if (MDocUpdater.GetMemberType (mi) != membertype) continue;
+
+ if (MDocUpdater.IsPrivate (mi))
+ continue;
+
+ IList<ParameterDefinition> pis = null;
+ string[] typeParams = null;
+ if (mi is MethodDefinition)
+ {
+ MethodDefinition mb = (MethodDefinition)mi;
+ pis = mb.Parameters;
+ if (mb.IsGenericMethod ())
+ {
+ IList<GenericParameter> args = mb.GenericParameters;
+ typeParams = args.Select (p => p.Name).ToArray ();
+ }
+ }
+ else if (mi is PropertyDefinition)
+ pis = ((PropertyDefinition)mi).Parameters;
+
+ // check type parameters
+ int methodTcount = member.TypeParameters == null ? 0 : member.TypeParameters.Count;
+ int reflectionTcount = typeParams == null ? 0 : typeParams.Length;
+ if (methodTcount != reflectionTcount)
+ continue;
+
+ // check member parameters
+ int mcount = member.Parameters == null ? 0 : member.Parameters.Count;
+ int pcount = pis == null ? 0 : pis.Count;
+ if (mcount != pcount)
+ continue;
+
+ MethodDefinition mDef = mi as MethodDefinition;
+ if (mDef != null && !mDef.IsConstructor)
+ {
+ // Casting operators can overload based on return type.
+ string rtype = GetReplacedString (
+ MDocUpdater.GetDocTypeFullName (((MethodDefinition)mi).ReturnType),
+ typeParams, docTypeParams);
+ string originalRType = rtype;
+ if (MDocUpdater.SwitchingToMagicTypes)
+ {
+ rtype = NativeTypeManager.ConvertFromNativeType (rtype);
+
+ }
+ if ((returntype != rtype && originalRType == rtype) ||
+ (MDocUpdater.SwitchingToMagicTypes && returntype != originalRType && returntype != rtype && originalRType != rtype))
+ {
+ continue;
+ }
+
+ if (originalRType != rtype)
+ matchedMagicType = true;
+ }
+
+ if (pcount == 0)
+ return mi;
+ bool good = true;
+ for (int i = 0; i < pis.Count; i++)
+ {
+ string paramType = GetReplacedString (
+ MDocUpdater.GetDocParameterType (pis[i].ParameterType),
+ typeParams, docTypeParams);
+
+ // if magictypes, replace paramType to "classic value" ... so the comparison works
+ string originalParamType = paramType;
+ if (MDocUpdater.SwitchingToMagicTypes)
+ {
+ paramType = NativeTypeManager.ConvertFromNativeType (paramType);
+ }
+
+ string xmlMemberType = member.Parameters[i];
+ if ((!paramType.Equals (xmlMemberType) && paramType.Equals (originalParamType)) ||
+ (MDocUpdater.SwitchingToMagicTypes && !originalParamType.Equals (xmlMemberType) && !paramType.Equals (xmlMemberType) && !paramType.Equals (originalParamType)))
+ {
+
+ // did not match ... if we're dropping the namespace, and the paramType has the dropped
+ // namespace, we should see if it matches when added
+ bool stillDoesntMatch = true;
+ if (MDocUpdater.HasDroppedNamespace (type) && paramType.StartsWith (MDocUpdater.droppedNamespace))
+ {
+ string withDroppedNs = string.Format ("{0}.{1}", MDocUpdater.droppedNamespace, xmlMemberType);
+
+ stillDoesntMatch = withDroppedNs != paramType;
+ }
+
+ if (stillDoesntMatch)
+ {
+ good = false;
+ break;
+ }
+ }
+
+ if (originalParamType != paramType)
+ matchedMagicType = true;
+ }
+ if (!good) continue;
+
+ if (MDocUpdater.SwitchingToMagicTypes && likelyCandidate == null && matchedMagicType)
+ {
+ // we matched this on a magic type conversion ... let's keep going to see if there's another one we should look at that matches more closely
+ likelyCandidate = mi;
+ continue;
+ }
+
+ return mi;
+ }
+
+ return likelyCandidate;
+ }
+
+ static string[] GetTypeParameters (string docName, IEnumerable<string> knownParameters)
+ {
+ if (docName[docName.Length - 1] != '>')
+ return null;
+ StringList types = new StringList ();
+ int endToken = docName.Length - 2;
+ int i = docName.Length - 2;
+ do
+ {
+ if (docName[i] == ',' || docName[i] == '<')
+ {
+ types.Add (docName.Substring (i + 1, endToken - i));
+ endToken = i - 1;
+ }
+ if (docName[i] == '<')
+ break;
+ } while (--i >= 0);
+
+ types.Reverse ();
+ var arrayTypes = types.ToArray ();
+
+ if (knownParameters != null && knownParameters.Any () && arrayTypes.Length != knownParameters.Count ())
+ return knownParameters.ToArray ();
+ else
+ return arrayTypes;
+ }
+
+ protected static IEnumerable<MemberReference> GetReflectionMembers (TypeDefinition type, string docName)
+ {
+ // In case of dropping the namespace, we have to remove the dropped NS
+ // so that docName will match what's in the assembly/type
+ if (MDocUpdater.HasDroppedNamespace (type) && docName.StartsWith (MDocUpdater.droppedNamespace + "."))
+ {
+ int droppedNsLength = MDocUpdater.droppedNamespace.Length;
+ docName = docName.Substring (droppedNsLength + 1, docName.Length - droppedNsLength - 1);
+ }
+
+ // need to worry about 4 forms of //@MemberName values:
+ // 1. "Normal" (non-generic) member names: GetEnumerator
+ // - Lookup as-is.
+ // 2. Explicitly-implemented interface member names: System.Collections.IEnumerable.Current
+ // - try as-is, and try type.member (due to "kludge" for property
+ // support.
+ // 3. "Normal" Generic member names: Sort<T> (CSC)
+ // - need to remove generic parameters --> "Sort"
+ // 4. Explicitly-implemented interface members for generic interfaces:
+ // -- System.Collections.Generic.IEnumerable<T>.Current
+ // - Try as-is, and try type.member, *keeping* the generic parameters.
+ // --> System.Collections.Generic.IEnumerable<T>.Current, IEnumerable<T>.Current
+ // 5. As of 2008-01-02, gmcs will do e.g. 'IFoo`1[A].Method' instead of
+ // 'IFoo<A>.Method' for explicitly implemented methods; don't interpret
+ // this as (1) or (2).
+ if (docName.IndexOf ('<') == -1 && docName.IndexOf ('[') == -1)
+ {
+ // Cases 1 & 2
+ foreach (MemberReference mi in type.GetMembers (docName))
+ yield return mi;
+ if (CountChars (docName, '.') > 0)
+ {
+
+ Func<MemberReference, bool> verifyInterface = (member) =>
+ {
+ var meth = member as MethodDefinition;
+
+ if (meth == null && member is PropertyReference)
+ {
+ var propertyDefinition = ((PropertyReference)member).Resolve ();
+ meth = propertyDefinition.GetMethod ?? propertyDefinition.SetMethod;
+ }
+ return meth != null && (member.Name.Equals (".ctor") || DocUtils.IsExplicitlyImplemented (meth));
+ };
+
+ int memberCount = 0;
+
+ // might be a property; try only type.member instead of
+ // namespace.type.member.
+ var typeMember = DocUtils.GetTypeDotMember (docName);
+ var memberName = DocUtils.GetMember (docName);
+ foreach (MemberReference mi in
+ type.GetMembers (typeMember).Where (verifyInterface))
+ {
+ memberCount++;
+ yield return mi;
+ }
+
+ // some VB libraries use just the member name
+ foreach (MemberReference mi in
+ type.GetMembers (memberName).Where (verifyInterface))
+ {
+ memberCount++;
+ yield return mi;
+ }
+
+ // some VB libraries use a `typemember` naming convention
+ foreach (MemberReference mi in
+ type.GetMembers (typeMember.Replace (".", "")).Where (verifyInterface))
+ {
+ memberCount++;
+ yield return mi;
+ }
+
+ // if we still haven't found the member, there are some VB libraries
+ // that use a different interface name for implementation.
+ if (memberCount == 0)
+ {
+ foreach (MemberReference mi in
+ type
+ .GetMembers ()
+ .Where (m => m.Name.StartsWith ("I", StringComparison.InvariantCultureIgnoreCase) && m.Name.EndsWith (memberName, StringComparison.InvariantCultureIgnoreCase))
+ .Where (verifyInterface))
+ yield return mi;
+ }
+ }
+ yield break;
+ }
+ // cases 3 & 4
+ int numLt = 0;
+ int numDot = 0;
+ int startLt, startType, startMethod;
+ startLt = startType = startMethod = -1;
+ for (int i = 0; i < docName.Length; ++i)
+ {
+ switch (docName[i])
+ {
+ case '<':
+ if (numLt == 0)
+ {
+ startLt = i;
+ }
+ ++numLt;
+ break;
+ case '>':
+ --numLt;
+ if (numLt == 0 && (i + 1) < docName.Length)
+ // there's another character in docName, so this <...> sequence is
+ // probably part of a generic type -- case 4.
+ startLt = -1;
+ break;
+ case '.':
+ startType = startMethod;
+ startMethod = i;
+ ++numDot;
+ break;
+ }
+ }
+ string refName = startLt == -1 ? docName : docName.Substring (0, startLt);
+ // case 3
+ foreach (MemberReference mi in type.GetMembers (refName))
+ yield return mi;
+
+ // case 4
+ foreach (MemberReference mi in type.GetMembers (refName.Substring (startType + 1)))
+ yield return mi;
+
+ // If we _still_ haven't found it, we've hit another generic naming issue:
+ // post Mono 1.1.18, gmcs generates [[FQTN]] instead of <TypeName> for
+ // explicitly-implemented METHOD names (not properties), e.g.
+ // "System.Collections.Generic.IEnumerable`1[[Foo, test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null]].GetEnumerator"
+ // instead of "System.Collections.Generic.IEnumerable<Foo>.GetEnumerator",
+ // which the XML docs will contain.
+ //
+ // Alas, we can't derive the Mono name from docName, so we need to iterate
+ // over all member names, convert them into CSC format, and compare... :-(
+ if (numDot == 0)
+ yield break;
+ foreach (MemberReference mi in type.GetMembers ())
+ {
+ if (MDocUpdater.GetMemberName (mi) == docName)
+ yield return mi;
+ }
+ }
+
+ static string GetReplacedString (string typeName, string[] from, string[] to)
+ {
+ if (from == null)
+ return typeName;
+ for (int i = 0; i < from.Length; ++i)
+ typeName = typeName.Replace (from[i], to[i]);
+ return typeName;
+ }
+
+ private static int CountChars (string s, char c)
+ {
+ int count = 0;
+ for (int i = 0; i < s.Length; ++i)
+ {
+ if (s[i] == c)
+ ++count;
+ }
+ return count;
+ }
+ }
+} \ No newline at end of file
diff --git a/mdoc/Mono.Documentation/Updater/DocumentationImporter.cs b/mdoc/Mono.Documentation/Updater/DocumentationImporter.cs
new file mode 100644
index 00000000..7c448ca4
--- /dev/null
+++ b/mdoc/Mono.Documentation/Updater/DocumentationImporter.cs
@@ -0,0 +1,8 @@
+namespace Mono.Documentation.Updater
+{
+ abstract class DocumentationImporter
+ {
+
+ public abstract void ImportDocumentation (DocsNodeInfo info);
+ }
+} \ No newline at end of file
diff --git a/mdoc/Mono.Documentation/Updater/DocumentationMember.cs b/mdoc/Mono.Documentation/Updater/DocumentationMember.cs
new file mode 100644
index 00000000..c581daeb
--- /dev/null
+++ b/mdoc/Mono.Documentation/Updater/DocumentationMember.cs
@@ -0,0 +1,151 @@
+using System;
+using System.Xml;
+using StringList = System.Collections.Generic.List<string>;
+using StringToStringMap = System.Collections.Generic.Dictionary<string, string>;
+
+namespace Mono.Documentation.Updater
+{
+ class DocumentationMember
+ {
+ public StringToStringMap MemberSignatures = new StringToStringMap ();
+ public string ReturnType;
+ public StringList Parameters;
+ public StringList TypeParameters;
+ public string MemberName;
+ public string MemberType;
+
+ /// <summary>Removes modreq and modopt from ReturnType, Parameters, and TypeParameters</summary>
+ private void CleanTypes ()
+ {
+ ReturnType = MemberFormatter.RemoveMod (ReturnType);
+ MemberType = MemberFormatter.RemoveMod (MemberType);
+
+ if (Parameters != null)
+ {
+ for (var i = 0; i < Parameters.Count; i++)
+ Parameters[i] = MemberFormatter.RemoveMod (Parameters[i]);
+ }
+
+ if (TypeParameters != null)
+ {
+ for (var i = 0; i < TypeParameters.Count; i++)
+ TypeParameters[i] = MemberFormatter.RemoveMod (TypeParameters[i]);
+ }
+ }
+
+ public DocumentationMember (XmlReader reader)
+ {
+ MemberName = reader.GetAttribute ("MemberName");
+ int depth = reader.Depth;
+ bool go = true;
+ StringList p = new StringList ();
+ StringList tp = new StringList ();
+ do
+ {
+ if (reader.NodeType != XmlNodeType.Element)
+ continue;
+
+ bool shouldUse = true;
+ try
+ {
+ string apistyle = reader.GetAttribute ("apistyle");
+ shouldUse = string.IsNullOrWhiteSpace (apistyle) || apistyle == "classic"; // only use this tag if it's an 'classic' style node
+ }
+ catch (Exception ex) { }
+ switch (reader.Name)
+ {
+ case "MemberSignature":
+ if (shouldUse)
+ {
+ MemberSignatures[reader.GetAttribute ("Language")] = reader.GetAttribute ("Value");
+ }
+ break;
+ case "MemberType":
+ MemberType = reader.ReadElementString ();
+ break;
+ case "ReturnType":
+ if (reader.Depth == depth + 2 && shouldUse)
+ ReturnType = reader.ReadElementString ();
+ break;
+ case "Parameter":
+ if (reader.Depth == depth + 2 && shouldUse)
+ p.Add (reader.GetAttribute ("Type"));
+ break;
+ case "TypeParameter":
+ if (reader.Depth == depth + 2 && shouldUse)
+ tp.Add (reader.GetAttribute ("Name"));
+ break;
+ case "Docs":
+ if (reader.Depth == depth + 1)
+ go = false;
+ break;
+ }
+ } while (go && reader.Read () && reader.Depth >= depth);
+ if (p.Count > 0)
+ {
+ Parameters = p;
+ }
+ if (tp.Count > 0)
+ {
+ TypeParameters = tp;
+ }
+ else
+ {
+ DiscernTypeParameters ();
+ }
+
+ CleanTypes ();
+ }
+
+ public DocumentationMember (XmlNode node)
+ {
+ MemberName = node.Attributes["MemberName"].Value;
+ foreach (XmlNode n in node.SelectNodes ("MemberSignature"))
+ {
+ XmlAttribute l = n.Attributes["Language"];
+ XmlAttribute v = n.Attributes["Value"];
+ XmlAttribute apistyle = n.Attributes["apistyle"];
+ bool shouldUse = apistyle == null || apistyle.Value == "classic";
+ if (l != null && v != null && shouldUse)
+ MemberSignatures[l.Value] = v.Value;
+ }
+ MemberType = node.SelectSingleNode ("MemberType").InnerText;
+ XmlNode rt = node.SelectSingleNode ("ReturnValue/ReturnType[not(@apistyle) or @apistyle='classic']");
+ if (rt != null)
+ ReturnType = rt.InnerText;
+ XmlNodeList p = node.SelectNodes ("Parameters/Parameter[not(@apistyle) or @apistyle='classic']");
+ if (p.Count > 0)
+ {
+ Parameters = new StringList (p.Count);
+ for (int i = 0; i < p.Count; ++i)
+ Parameters.Add (p[i].Attributes["Type"].Value);
+ }
+ XmlNodeList tp = node.SelectNodes ("TypeParameters/TypeParameter[not(@apistyle) or @apistyle='classic']");
+ if (tp.Count > 0)
+ {
+ TypeParameters = new StringList (tp.Count);
+ for (int i = 0; i < tp.Count; ++i)
+ TypeParameters.Add (tp[i].Attributes["Name"].Value);
+ }
+ else
+ {
+ DiscernTypeParameters ();
+ }
+
+ CleanTypes ();
+ }
+
+ void DiscernTypeParameters ()
+ {
+ // see if we can discern the param list from the name
+ if (MemberName.Contains ("<") && MemberName.EndsWith (">"))
+ {
+ var starti = MemberName.IndexOf ("<") + 1;
+ var endi = MemberName.LastIndexOf (">");
+ var paramlist = MemberName.Substring (starti, endi - starti);
+ var tparams = paramlist.Split (new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
+ TypeParameters = new StringList (tparams);
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/mdoc/Mono.Documentation/Updater/DynamicParserContext.cs b/mdoc/Mono.Documentation/Updater/DynamicParserContext.cs
new file mode 100644
index 00000000..898ecaf9
--- /dev/null
+++ b/mdoc/Mono.Documentation/Updater/DynamicParserContext.cs
@@ -0,0 +1,30 @@
+using System.Collections.ObjectModel;
+using System.Linq;
+
+using Mono.Cecil;
+
+using Mono.Documentation.Util;
+
+namespace Mono.Documentation.Updater
+{
+ public class DynamicParserContext
+ {
+ public ReadOnlyCollection<bool> TransformFlags;
+ public int TransformIndex;
+
+ public DynamicParserContext (ICustomAttributeProvider provider)
+ {
+ CustomAttribute da;
+ if (provider.HasCustomAttributes &&
+ (da = (provider.CustomAttributes.Cast<CustomAttribute> ()
+ .SingleOrDefault (ca => ca.GetDeclaringType () == "System.Runtime.CompilerServices.DynamicAttribute"))) != null)
+ {
+ CustomAttributeArgument[] values = da.ConstructorArguments.Count == 0
+ ? new CustomAttributeArgument[0]
+ : (CustomAttributeArgument[])da.ConstructorArguments[0].Value;
+
+ TransformFlags = new ReadOnlyCollection<bool> (values.Select (t => (bool)t.Value).ToArray ());
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/mdoc/Mono.Documentation/Updater/EcmaDocumentationEnumerator.cs b/mdoc/Mono.Documentation/Updater/EcmaDocumentationEnumerator.cs
new file mode 100644
index 00000000..86cce337
--- /dev/null
+++ b/mdoc/Mono.Documentation/Updater/EcmaDocumentationEnumerator.cs
@@ -0,0 +1,169 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Xml;
+
+using Mono.Cecil;
+
+using Mono.Documentation.Util;
+
+namespace Mono.Documentation.Updater
+{
+ class EcmaDocumentationEnumerator : DocumentationEnumerator
+ {
+
+ XmlReader ecmadocs;
+ MDocUpdater app;
+
+ public EcmaDocumentationEnumerator (MDocUpdater app, XmlReader ecmaDocs)
+ {
+ this.app = app;
+ this.ecmadocs = ecmaDocs;
+ }
+
+ public override IEnumerable<TypeDefinition> GetDocumentationTypes (AssemblyDefinition assembly, List<string> forTypes)
+ {
+ HashSet<string> seen = new HashSet<string> ();
+ return GetDocumentationTypes (assembly, forTypes, seen)
+ .Concat (base.GetDocumentationTypes (assembly, forTypes, seen));
+ }
+
+ new IEnumerable<TypeDefinition> GetDocumentationTypes (AssemblyDefinition assembly, List<string> forTypes, HashSet<string> seen)
+ {
+ int typeDepth = -1;
+ while (ecmadocs.Read ())
+ {
+ switch (ecmadocs.Name)
+ {
+ case "Type":
+ {
+ if (typeDepth == -1)
+ typeDepth = ecmadocs.Depth;
+ if (ecmadocs.NodeType != XmlNodeType.Element)
+ continue;
+ if (typeDepth != ecmadocs.Depth) // nested <TypeDefinition/> element?
+ continue;
+ string typename = ecmadocs.GetAttribute ("FullName");
+ string typename2 = MDocUpdater.GetTypeFileName (typename);
+ if (forTypes != null &&
+ forTypes.BinarySearch (typename) < 0 &&
+ typename != typename2 &&
+ forTypes.BinarySearch (typename2) < 0)
+ continue;
+ TypeDefinition t;
+ if ((t = assembly.GetType (typename)) == null &&
+ (t = assembly.GetType (typename2)) == null)
+ continue;
+ seen.Add (typename);
+ if (typename != typename2)
+ seen.Add (typename2);
+ Console.WriteLine (" Import: {0}", t.FullName);
+ if (ecmadocs.Name != "Docs")
+ {
+ int depth = ecmadocs.Depth;
+ while (ecmadocs.Read ())
+ {
+ if (ecmadocs.Name == "Docs" && ecmadocs.Depth == depth + 1)
+ break;
+ }
+ }
+ if (!ecmadocs.IsStartElement ("Docs"))
+ throw new InvalidOperationException ("Found " + ecmadocs.Name + "; expecting <Docs/>!");
+ yield return t;
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ }
+
+ public override IEnumerable<DocsNodeInfo> GetDocumentationMembers (XmlDocument basefile, TypeDefinition type)
+ {
+ return GetMembers (basefile, type)
+ .Concat (base.GetDocumentationMembers (basefile, type));
+ }
+
+ private IEnumerable<DocsNodeInfo> GetMembers (XmlDocument basefile, TypeDefinition type)
+ {
+ while (ecmadocs.Name != "Members" && ecmadocs.Read ())
+ {
+ // do nothing
+ }
+ if (ecmadocs.IsEmptyElement)
+ yield break;
+
+ int membersDepth = ecmadocs.Depth;
+ bool go = true;
+ while (go && ecmadocs.Read ())
+ {
+ switch (ecmadocs.Name)
+ {
+ case "Member":
+ {
+ if (membersDepth != ecmadocs.Depth - 1 || ecmadocs.NodeType != XmlNodeType.Element)
+ continue;
+ DocumentationMember dm = new DocumentationMember (ecmadocs);
+
+ string xp = MDocUpdater.GetXPathForMember (dm);
+ XmlElement oldmember = (XmlElement)basefile.SelectSingleNode (xp);
+ MemberReference m;
+ if (oldmember == null)
+ {
+ m = GetMember (type, dm);
+ if (m == null)
+ {
+ app.Warning ("Could not import ECMA docs for `{0}'s `{1}': Member not found.",
+ type.FullName, dm.MemberSignatures["C#"]);
+ // SelectSingleNode (ecmaDocsMember, "MemberSignature[@Language=\"C#\"]/@Value").Value);
+ continue;
+ }
+ // oldmember lookup may have failed due to type parameter renames.
+ // Try again.
+ oldmember = (XmlElement)basefile.SelectSingleNode (MDocUpdater.GetXPathForMember (m));
+ if (oldmember == null)
+ {
+ XmlElement members = MDocUpdater.WriteElement (basefile.DocumentElement, "Members");
+ oldmember = basefile.CreateElement ("Member");
+ oldmember.SetAttribute ("MemberName", dm.MemberName);
+ members.AppendChild (oldmember);
+ foreach (string key in MDocUpdater.Sort (dm.MemberSignatures.Keys))
+ {
+ XmlElement ms = basefile.CreateElement ("MemberSignature");
+ ms.SetAttribute ("Language", key);
+ ms.SetAttribute ("Value", (string)dm.MemberSignatures[key]);
+ oldmember.AppendChild (ms);
+ }
+ oldmember.SetAttribute ("__monodocer-seen__", "true");
+ Console.WriteLine ("Member Added: {0}", oldmember.SelectSingleNode ("MemberSignature[@Language='C#']/@Value").InnerText);
+ app.additions++;
+ }
+ }
+ else
+ {
+ m = GetMember (type, new DocumentationMember (oldmember));
+ if (m == null)
+ {
+ app.Warning ("Could not import ECMA docs for `{0}'s `{1}': Member not found.",
+ type.FullName, dm.MemberSignatures["C#"]);
+ continue;
+ }
+ oldmember.SetAttribute ("__monodocer-seen__", "true");
+ }
+ DocsNodeInfo node = new DocsNodeInfo (oldmember, m);
+ if (ecmadocs.Name != "Docs")
+ throw new InvalidOperationException ("Found " + ecmadocs.Name + "; expected <Docs/>!");
+ yield return node;
+ break;
+ }
+ case "Members":
+ if (membersDepth == ecmadocs.Depth && ecmadocs.NodeType == XmlNodeType.EndElement)
+ {
+ go = false;
+ }
+ break;
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/mdoc/Mono.Documentation/Updater/EcmaDocumentationImporter.cs b/mdoc/Mono.Documentation/Updater/EcmaDocumentationImporter.cs
new file mode 100644
index 00000000..34210577
--- /dev/null
+++ b/mdoc/Mono.Documentation/Updater/EcmaDocumentationImporter.cs
@@ -0,0 +1,118 @@
+using System;
+using System.Xml;
+
+using StringList = System.Collections.Generic.List<string>;
+
+namespace Mono.Documentation.Updater
+{
+ class EcmaDocumentationImporter : DocumentationImporter
+ {
+
+ XmlReader ecmadocs;
+
+ public EcmaDocumentationImporter (XmlReader ecmaDocs)
+ {
+ this.ecmadocs = ecmaDocs;
+ }
+
+ public override void ImportDocumentation (DocsNodeInfo info)
+ {
+ if (!ecmadocs.IsStartElement ("Docs"))
+ {
+ return;
+ }
+
+ XmlElement e = info.Node;
+
+ int depth = ecmadocs.Depth;
+ ecmadocs.ReadStartElement ("Docs");
+ while (ecmadocs.Read ())
+ {
+ if (ecmadocs.Name == "Docs")
+ {
+ if (ecmadocs.Depth == depth && ecmadocs.NodeType == XmlNodeType.EndElement)
+ break;
+ else
+ throw new InvalidOperationException ("Skipped past current <Docs/> element!");
+ }
+ if (!ecmadocs.IsStartElement ())
+ continue;
+ switch (ecmadocs.Name)
+ {
+ case "param":
+ case "typeparam":
+ {
+ string name = ecmadocs.GetAttribute ("name");
+ if (name == null)
+ break;
+ XmlNode doc = e.SelectSingleNode (
+ ecmadocs.Name + "[@name='" + name + "']");
+ string value = ecmadocs.ReadInnerXml ();
+ if (doc != null)
+ doc.InnerXml = value.Replace ("\r", "");
+ break;
+ }
+ case "altmember":
+ case "exception":
+ case "permission":
+ case "seealso":
+ {
+ string name = ecmadocs.Name;
+ string cref = ecmadocs.GetAttribute ("cref");
+ if (cref == null)
+ break;
+ XmlNode doc = e.SelectSingleNode (
+ ecmadocs.Name + "[@cref='" + cref + "']");
+ string value = ecmadocs.ReadInnerXml ().Replace ("\r", "");
+ if (doc != null)
+ doc.InnerXml = value;
+ else
+ {
+ XmlElement n = e.OwnerDocument.CreateElement (name);
+ n.SetAttribute ("cref", cref);
+ n.InnerXml = value;
+ e.AppendChild (n);
+ }
+ break;
+ }
+ default:
+ {
+ string name = ecmadocs.Name;
+ string xpath = ecmadocs.Name;
+ StringList attributes = new StringList (ecmadocs.AttributeCount);
+ if (ecmadocs.MoveToFirstAttribute ())
+ {
+ do
+ {
+ attributes.Add ("@" + ecmadocs.Name + "=\"" + ecmadocs.Value + "\"");
+ } while (ecmadocs.MoveToNextAttribute ());
+ ecmadocs.MoveToContent ();
+ }
+ if (attributes.Count > 0)
+ {
+ xpath += "[" + string.Join (" and ", attributes.ToArray ()) + "]";
+ }
+ XmlNode doc = e.SelectSingleNode (xpath);
+ string value = ecmadocs.ReadInnerXml ().Replace ("\r", "");
+ if (doc != null)
+ {
+ doc.InnerXml = value;
+ }
+ else
+ {
+ XmlElement n = e.OwnerDocument.CreateElement (name);
+ n.InnerXml = value;
+ foreach (string a in attributes)
+ {
+ int eq = a.IndexOf ('=');
+ n.SetAttribute (a.Substring (1, eq - 1), a.Substring (eq + 2, a.Length - eq - 3));
+ }
+ e.AppendChild (n);
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/mdoc/Mono.Documentation/Updater/Formatters/ApplePlatformEnumFormatter.cs b/mdoc/Mono.Documentation/Updater/Formatters/ApplePlatformEnumFormatter.cs
new file mode 100644
index 00000000..ec3485df
--- /dev/null
+++ b/mdoc/Mono.Documentation/Updater/Formatters/ApplePlatformEnumFormatter.cs
@@ -0,0 +1,95 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+using Mono.Cecil;
+
+namespace Mono.Documentation.Updater
+{
+ /// <summary>A custom formatter for the ObjCRuntime.Platform enumeration.</summary>
+ class ApplePlatformEnumFormatter : AttributeValueFormatter
+ {
+ public override bool TryFormatValue (object v, ResolvedTypeInfo type, out string returnvalue)
+ {
+ TypeReference valueType = type.Reference;
+ string typename = MDocUpdater.GetDocTypeFullName (valueType);
+ TypeDefinition valueDef = type.Definition;
+ if (typename.Contains ("ObjCRuntime.Platform") && valueDef.CustomAttributes.Any (ca => ca.AttributeType.FullName == "System.FlagsAttribute"))
+ {
+
+ var values = MDocUpdater.GetEnumerationValues (valueDef);
+ long c = MDocUpdater.ToInt64 (v);
+
+ returnvalue = Format (c, values, typename);
+ return true;
+ }
+
+ returnvalue = null;
+ return false;
+ }
+
+ string Format (long c, IDictionary<long, string> values, string typename)
+ {
+ int iosarch, iosmajor, iosminor, iossubminor;
+ int macarch, macmajor, macminor, macsubminor;
+ GetEncodingiOS (c, out iosarch, out iosmajor, out iosminor, out iossubminor);
+ GetEncodingMac ((ulong)c, out macarch, out macmajor, out macminor, out macsubminor);
+
+ if (iosmajor == 0 & iosminor == 0 && iossubminor == 0)
+ {
+ return FormatValues ("Mac", macarch, macmajor, macminor, macsubminor);
+ }
+
+ if (macmajor == 0 & macminor == 0 && macsubminor == 0)
+ {
+ return FormatValues ("iOS", iosarch, iosmajor, iosminor, iossubminor);
+ }
+
+ return string.Format ("(Platform){0}", c);
+ }
+
+ string FormatValues (string plat, int arch, int major, int minor, int subminor)
+ {
+ string archstring = "";
+ switch (arch)
+ {
+ case 1:
+ archstring = "32";
+ break;
+ case 2:
+ archstring = "64";
+ break;
+ }
+ return string.Format ("Platform.{4}_{0}_{1}{2} | Platform.{4}_Arch{3}",
+ major,
+ minor,
+ subminor == 0 ? "" : "_" + subminor.ToString (),
+ archstring,
+ plat
+ );
+ }
+
+ void GetEncodingiOS (long entireLong, out int archindex, out int major, out int minor, out int subminor)
+ {
+ long lowerBits = entireLong & 0xffffffff;
+ int lowerBitsAsInt = (int)lowerBits;
+ GetEncoding (lowerBitsAsInt, out archindex, out major, out minor, out subminor);
+ }
+
+ void GetEncodingMac (ulong entireLong, out int archindex, out int major, out int minor, out int subminor)
+ {
+ ulong higherBits = entireLong & 0xffffffff00000000;
+ int higherBitsAsInt = (int)((higherBits) >> 32);
+ GetEncoding (higherBitsAsInt, out archindex, out major, out minor, out subminor);
+ }
+
+ void GetEncoding (Int32 encodedBits, out int archindex, out int major, out int minor, out int subminor)
+ {
+ // format is AAJJNNSS
+ archindex = (int)((encodedBits & 0xFF000000) >> 24);
+ major = (int)((encodedBits & 0x00FF0000) >> 16);
+ minor = (int)((encodedBits & 0x0000FF00) >> 8);
+ subminor = (int)((encodedBits & 0x000000FF) >> 0);
+ }
+ }
+} \ No newline at end of file
diff --git a/mdoc/Mono.Documentation/Updater/Formatters/AttributeValueFormatter.cs b/mdoc/Mono.Documentation/Updater/Formatters/AttributeValueFormatter.cs
new file mode 100644
index 00000000..4c41f9a7
--- /dev/null
+++ b/mdoc/Mono.Documentation/Updater/Formatters/AttributeValueFormatter.cs
@@ -0,0 +1,66 @@
+using System;
+
+using Mono.Cecil;
+
+using Mono.Documentation.Util;
+
+namespace Mono.Documentation.Updater
+{
+ /// <summary>Formats attribute values. Should return true if it is able to format the value.</summary>
+ class AttributeValueFormatter
+ {
+ public virtual bool TryFormatValue (object v, ResolvedTypeInfo type, out string returnvalue)
+ {
+ TypeReference valueType = type.Reference;
+ if (v == null)
+ {
+ returnvalue = "null";
+ return true;
+ }
+ if (valueType.FullName == "System.Type")
+ {
+ var vTypeRef = v as TypeReference;
+ if (vTypeRef != null)
+ returnvalue = "typeof(" + NativeTypeManager.GetTranslatedName (vTypeRef) + ")"; // TODO: drop NS handling
+ else
+ returnvalue = "typeof(" + v.ToString () + ")";
+
+ return true;
+ }
+ if (valueType.FullName == "System.String")
+ {
+ returnvalue = "\"" + v.ToString () + "\"";
+ return true;
+ }
+ if (valueType.FullName == "System.Char")
+ {
+ returnvalue = "'" + v.ToString () + "'";
+ return true;
+ }
+ if (v is Boolean)
+ {
+ returnvalue = (bool)v ? "true" : "false";
+ return true;
+ }
+
+ TypeDefinition valueDef = type.Definition;
+ if (valueDef == null || !valueDef.IsEnum)
+ {
+ returnvalue = v.ToString ();
+ return true;
+ }
+
+ string typename = MDocUpdater.GetDocTypeFullName (valueType);
+ var values = MDocUpdater.GetEnumerationValues (valueDef);
+ long c = MDocUpdater.ToInt64 (v);
+ if (values.ContainsKey (c))
+ {
+ returnvalue = typename + "." + values[c];
+ return true;
+ }
+
+ returnvalue = null;
+ return false;
+ }
+ }
+} \ No newline at end of file
diff --git a/mdoc/Mono.Documentation/Updater/Formatters/CSharpFullMemberFormatter.cs b/mdoc/Mono.Documentation/Updater/Formatters/CSharpFullMemberFormatter.cs
new file mode 100644
index 00000000..5e89539d
--- /dev/null
+++ b/mdoc/Mono.Documentation/Updater/Formatters/CSharpFullMemberFormatter.cs
@@ -0,0 +1,659 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Text;
+
+using Mono.Cecil;
+
+using Mono.Documentation.Util;
+
+namespace Mono.Documentation.Updater
+{
+ public class CSharpFullMemberFormatter : MemberFormatter
+ {
+
+ public override string Language
+ {
+ get { return "C#"; }
+ }
+
+ protected override StringBuilder AppendNamespace (StringBuilder buf, TypeReference type)
+ {
+
+ string ns = DocUtils.GetNamespace (type);
+ if (GetCSharpType (type.FullName) == null && ns != null && ns.Length > 0 && ns != "System")
+ buf.Append (ns).Append ('.');
+ return buf;
+ }
+
+ protected virtual string GetCSharpType (string t)
+ {
+ // make sure there are no modifiers in the type string (add them back before returning)
+ string typeToCompare = t;
+ string[] splitType = null;
+ if (t.Contains (' '))
+ {
+ splitType = t.Split (' ');
+ typeToCompare = splitType[0];
+ }
+
+ switch (typeToCompare)
+ {
+ case "System.Byte": typeToCompare = "byte"; break;
+ case "System.SByte": typeToCompare = "sbyte"; break;
+ case "System.Int16": typeToCompare = "short"; break;
+ case "System.Int32": typeToCompare = "int"; break;
+ case "System.Int64": typeToCompare = "long"; break;
+
+ case "System.UInt16": typeToCompare = "ushort"; break;
+ case "System.UInt32": typeToCompare = "uint"; break;
+ case "System.UInt64": typeToCompare = "ulong"; break;
+
+ case "System.Single": typeToCompare = "float"; break;
+ case "System.Double": typeToCompare = "double"; break;
+ case "System.Decimal": typeToCompare = "decimal"; break;
+ case "System.Boolean": typeToCompare = "bool"; break;
+ case "System.Char": typeToCompare = "char"; break;
+ case "System.Void": typeToCompare = "void"; break;
+ case "System.String": typeToCompare = "string"; break;
+ case "System.Object": typeToCompare = "object"; break;
+ }
+
+ if (splitType != null)
+ {
+ // re-add modreq/modopt if it was there
+ splitType[0] = typeToCompare;
+ typeToCompare = string.Join (" ", splitType);
+ }
+ return typeToCompare == t ? null : typeToCompare;
+ }
+
+ protected override StringBuilder AppendTypeName (StringBuilder buf, TypeReference type, DynamicParserContext context)
+ {
+ if (context != null && context.TransformFlags != null &&
+ (context.TransformFlags.Count == 0 || context.TransformFlags[context.TransformIndex]))
+ {
+ context.TransformIndex++;
+ return buf.Append ("dynamic");
+ }
+
+ if (type is GenericParameter)
+ return AppendGenericParameterConstraints (buf, (GenericParameter)type, context).Append (type.Name);
+ string t = type.FullName;
+ if (!t.StartsWith ("System."))
+ {
+ return base.AppendTypeName (buf, type, context);
+ }
+
+ string s = GetCSharpType (t);
+ if (s != null)
+ {
+ if (context != null)
+ context.TransformIndex++;
+ return buf.Append (s);
+ }
+
+ return base.AppendTypeName (buf, type, context);
+ }
+
+ private StringBuilder AppendGenericParameterConstraints (StringBuilder buf, GenericParameter type, DynamicParserContext context)
+ {
+ if (MemberFormatterState != MemberFormatterState.WithinGenericTypeParameters)
+ return buf;
+ GenericParameterAttributes attrs = type.Attributes;
+ bool isout = (attrs & GenericParameterAttributes.Covariant) != 0;
+ bool isin = (attrs & GenericParameterAttributes.Contravariant) != 0;
+ if (isin)
+ buf.Append ("in ");
+ else if (isout)
+ buf.Append ("out ");
+ return buf;
+ }
+
+ protected override string GetTypeDeclaration (TypeDefinition type)
+ {
+ string visibility = GetTypeVisibility (type.Attributes);
+ if (visibility == null)
+ return null;
+
+ StringBuilder buf = new StringBuilder ();
+
+ buf.Append (visibility);
+ buf.Append (" ");
+
+ MemberFormatter full = new CSharpFullMemberFormatter ();
+
+ if (DocUtils.IsDelegate (type))
+ {
+ buf.Append ("delegate ");
+ MethodDefinition invoke = type.GetMethod ("Invoke");
+ buf.Append (full.GetName (invoke.ReturnType, new DynamicParserContext (invoke.MethodReturnType))).Append (" ");
+ buf.Append (GetName (type));
+ AppendParameters (buf, invoke, invoke.Parameters);
+ AppendGenericTypeConstraints (buf, type);
+ buf.Append (";");
+
+ return buf.ToString ();
+ }
+
+ if (type.IsAbstract && !type.IsInterface)
+ buf.Append ("abstract ");
+ if (type.IsSealed && !DocUtils.IsDelegate (type) && !type.IsValueType)
+ buf.Append ("sealed ");
+ buf.Replace ("abstract sealed", "static");
+
+ buf.Append (GetTypeKind (type));
+ buf.Append (" ");
+ buf.Append (GetCSharpType (type.FullName) == null
+ ? GetName (type)
+ : type.Name);
+
+ if (!type.IsEnum)
+ {
+ TypeReference basetype = type.BaseType;
+ if (basetype != null && basetype.FullName == "System.Object" || type.IsValueType) // FIXME
+ basetype = null;
+
+ List<string> interface_names = DocUtils.GetUserImplementedInterfaces (type)
+ .Select (iface => full.GetName (iface))
+ .OrderBy (s => s)
+ .ToList ();
+
+ if (basetype != null || interface_names.Count > 0)
+ buf.Append (" : ");
+
+ if (basetype != null)
+ {
+ buf.Append (full.GetName (basetype));
+ if (interface_names.Count > 0)
+ buf.Append (", ");
+ }
+
+ for (int i = 0; i < interface_names.Count; i++)
+ {
+ if (i != 0)
+ buf.Append (", ");
+ buf.Append (interface_names[i]);
+ }
+ AppendGenericTypeConstraints (buf, type);
+ }
+
+ return buf.ToString ();
+ }
+
+ static string GetTypeKind (TypeDefinition t)
+ {
+ if (t.IsEnum)
+ return "enum";
+ if (t.IsValueType)
+ return "struct";
+ if (t.IsClass || t.FullName == "System.Enum")
+ return "class";
+ if (t.IsInterface)
+ return "interface";
+ throw new ArgumentException (t.FullName);
+ }
+
+ static string GetTypeVisibility (TypeAttributes ta)
+ {
+ switch (ta & TypeAttributes.VisibilityMask)
+ {
+ case TypeAttributes.Public:
+ case TypeAttributes.NestedPublic:
+ return "public";
+
+ case TypeAttributes.NestedFamily:
+ case TypeAttributes.NestedFamORAssem:
+ return "protected";
+
+ default:
+ return null;
+ }
+ }
+
+ protected override StringBuilder AppendGenericTypeConstraints (StringBuilder buf, TypeReference type)
+ {
+ if (type.GenericParameters.Count == 0)
+ return buf;
+ return AppendConstraints (buf, type.GenericParameters);
+ }
+
+ private StringBuilder AppendConstraints (StringBuilder buf, IList<GenericParameter> genArgs)
+ {
+ foreach (GenericParameter genArg in genArgs)
+ {
+ GenericParameterAttributes attrs = genArg.Attributes;
+ IList<TypeReference> constraints = genArg.Constraints;
+ if (attrs == GenericParameterAttributes.NonVariant && constraints.Count == 0)
+ continue;
+
+ bool isref = (attrs & GenericParameterAttributes.ReferenceTypeConstraint) != 0;
+ bool isvt = (attrs & GenericParameterAttributes.NotNullableValueTypeConstraint) != 0;
+ bool isnew = (attrs & GenericParameterAttributes.DefaultConstructorConstraint) != 0;
+ bool comma = false;
+
+ if (!isref && !isvt && !isnew && constraints.Count == 0)
+ continue;
+ buf.Append (" where ").Append (genArg.Name).Append (" : ");
+ if (isref)
+ {
+ buf.Append ("class");
+ comma = true;
+ }
+ else if (isvt)
+ {
+ buf.Append ("struct");
+ comma = true;
+ }
+ if (constraints.Count > 0 && !isvt)
+ {
+ if (comma)
+ buf.Append (", ");
+ buf.Append (GetTypeName (constraints[0]));
+ for (int i = 1; i < constraints.Count; ++i)
+ buf.Append (", ").Append (GetTypeName (constraints[i]));
+ }
+ if (isnew && !isvt)
+ {
+ if (comma)
+ buf.Append (", ");
+ buf.Append ("new()");
+ }
+ }
+ return buf;
+ }
+
+ protected override string GetConstructorDeclaration (MethodDefinition constructor)
+ {
+ StringBuilder buf = new StringBuilder ();
+ AppendVisibility (buf, constructor);
+ if (buf.Length == 0)
+ return null;
+
+ buf.Append (' ');
+ base.AppendTypeName (buf, constructor.DeclaringType.Name).Append (' ');
+ AppendParameters (buf, constructor, constructor.Parameters);
+ buf.Append (';');
+
+ return buf.ToString ();
+ }
+
+ protected override string GetMethodDeclaration (MethodDefinition method)
+ {
+ string decl = base.GetMethodDeclaration (method);
+ if (decl != null)
+ return decl + ";";
+ return null;
+ }
+
+ protected override StringBuilder AppendMethodName (StringBuilder buf, MethodDefinition method)
+ {
+ if (DocUtils.IsExplicitlyImplemented (method))
+ {
+ TypeReference iface;
+ MethodReference ifaceMethod;
+ DocUtils.GetInfoForExplicitlyImplementedMethod (method, out iface, out ifaceMethod);
+ return buf.Append (new CSharpMemberFormatter ().GetName (iface))
+ .Append ('.')
+ .Append (ifaceMethod.Name);
+ }
+
+ if (method.Name.StartsWith ("op_", StringComparison.Ordinal))
+ {
+ // this is an operator
+ switch (method.Name)
+ {
+ case "op_Implicit":
+ case "op_Explicit":
+ buf.Length--; // remove the last space, which assumes a member name is coming
+ return buf;
+ case "op_Addition":
+ case "op_UnaryPlus":
+ return buf.Append ("operator +");
+ case "op_Subtraction":
+ case "op_UnaryNegation":
+ return buf.Append ("operator -");
+ case "op_Division":
+ return buf.Append ("operator /");
+ case "op_Multiply":
+ return buf.Append ("operator *");
+ case "op_Modulus":
+ return buf.Append ("operator %");
+ case "op_BitwiseAnd":
+ return buf.Append ("operator &");
+ case "op_BitwiseOr":
+ return buf.Append ("operator |");
+ case "op_ExclusiveOr":
+ return buf.Append ("operator ^");
+ case "op_LeftShift":
+ return buf.Append ("operator <<");
+ case "op_RightShift":
+ return buf.Append ("operator >>");
+ case "op_LogicalNot":
+ return buf.Append ("operator !");
+ case "op_OnesComplement":
+ return buf.Append ("operator ~");
+ case "op_Decrement":
+ return buf.Append ("operator --");
+ case "op_Increment":
+ return buf.Append ("operator ++");
+ case "op_True":
+ return buf.Append ("operator true");
+ case "op_False":
+ return buf.Append ("operator false");
+ case "op_Equality":
+ return buf.Append ("operator ==");
+ case "op_Inequality":
+ return buf.Append ("operator !=");
+ case "op_LessThan":
+ return buf.Append ("operator <");
+ case "op_LessThanOrEqual":
+ return buf.Append ("operator <=");
+ case "op_GreaterThan":
+ return buf.Append ("operator >");
+ case "op_GreaterThanOrEqual":
+ return buf.Append ("operator >=");
+ default:
+ return base.AppendMethodName (buf, method);
+ }
+ }
+ else
+ return base.AppendMethodName (buf, method);
+ }
+
+ protected override StringBuilder AppendGenericMethodConstraints (StringBuilder buf, MethodDefinition method)
+ {
+ if (method.GenericParameters.Count == 0)
+ return buf;
+ return AppendConstraints (buf, method.GenericParameters);
+ }
+
+ protected override string RefTypeModifier
+ {
+ get { return ""; }
+ }
+
+ protected override string GetFinalizerName (MethodDefinition method)
+ {
+ return "~" + method.DeclaringType.Name + " ()";
+ }
+
+ protected override StringBuilder AppendVisibility (StringBuilder buf, MethodDefinition method)
+ {
+ if (method == null)
+ return buf;
+ if (method.IsPublic)
+ return buf.Append ("public");
+ if (method.IsFamily || method.IsFamilyOrAssembly)
+ return buf.Append ("protected");
+ return buf;
+ }
+
+ protected override StringBuilder AppendModifiers (StringBuilder buf, MethodDefinition method)
+ {
+ string modifiers = String.Empty;
+ if (method.IsStatic) modifiers += " static";
+ if (method.IsVirtual && !method.IsAbstract)
+ {
+ if ((method.Attributes & MethodAttributes.NewSlot) != 0) modifiers += " virtual";
+ else modifiers += " override";
+ }
+ TypeDefinition declType = (TypeDefinition)method.DeclaringType;
+ if (method.IsAbstract && !declType.IsInterface) modifiers += " abstract";
+ if (method.IsFinal) modifiers += " sealed";
+ if (modifiers == " virtual sealed") modifiers = "";
+
+ switch (method.Name)
+ {
+ case "op_Implicit":
+ modifiers += " implicit operator";
+ break;
+ case "op_Explicit":
+ modifiers += " explicit operator";
+ break;
+ }
+
+ return buf.Append (modifiers);
+ }
+
+ protected override StringBuilder AppendGenericMethod (StringBuilder buf, MethodDefinition method)
+ {
+ if (method.IsGenericMethod ())
+ {
+ IList<GenericParameter> args = method.GenericParameters;
+ if (args.Count > 0)
+ {
+ buf.Append ("<");
+ buf.Append (args[0].Name);
+ for (int i = 1; i < args.Count; ++i)
+ buf.Append (",").Append (args[i].Name);
+ buf.Append (">");
+ }
+ }
+ return buf;
+ }
+
+ protected override StringBuilder AppendParameters (StringBuilder buf, MethodDefinition method, IList<ParameterDefinition> parameters)
+ {
+ return AppendParameters (buf, method, parameters, '(', ')');
+ }
+
+ private StringBuilder AppendParameters (StringBuilder buf, MethodDefinition method, IList<ParameterDefinition> parameters, char begin, char end)
+ {
+ buf.Append (begin);
+
+ if (parameters.Count > 0)
+ {
+ if (DocUtils.IsExtensionMethod (method))
+ buf.Append ("this ");
+ AppendParameter (buf, parameters[0]);
+ for (int i = 1; i < parameters.Count; ++i)
+ {
+ buf.Append (", ");
+ AppendParameter (buf, parameters[i]);
+ }
+ }
+
+ return buf.Append (end);
+ }
+
+ private StringBuilder AppendParameter (StringBuilder buf, ParameterDefinition parameter)
+ {
+ if (parameter.ParameterType is ByReferenceType)
+ {
+ if (parameter.IsOut)
+ buf.Append ("out ");
+ else
+ buf.Append ("ref ");
+ }
+ if (parameter.HasCustomAttributes)
+ {
+ var isParams = parameter.CustomAttributes.Any (ca => ca.AttributeType.Name == "ParamArrayAttribute");
+ if (isParams)
+ buf.AppendFormat ("params ");
+ }
+ buf.Append (GetTypeName (parameter.ParameterType, new DynamicParserContext (parameter))).Append (" ");
+ buf.Append (parameter.Name);
+ if (parameter.HasDefault && parameter.IsOptional && parameter.HasConstant)
+ {
+ buf.AppendFormat (" = {0}", MDocUpdater.MakeAttributesValueString (parameter.Constant, parameter.ParameterType));
+ }
+ return buf;
+ }
+
+ protected override string GetPropertyDeclaration (PropertyDefinition property)
+ {
+ MethodDefinition method;
+
+ string get_visible = null;
+ if ((method = property.GetMethod) != null &&
+ (DocUtils.IsExplicitlyImplemented (method) ||
+ (!method.IsPrivate && !method.IsAssembly && !method.IsFamilyAndAssembly)))
+ get_visible = AppendVisibility (new StringBuilder (), method).ToString ();
+ string set_visible = null;
+ if ((method = property.SetMethod) != null &&
+ (DocUtils.IsExplicitlyImplemented (method) ||
+ (!method.IsPrivate && !method.IsAssembly && !method.IsFamilyAndAssembly)))
+ set_visible = AppendVisibility (new StringBuilder (), method).ToString ();
+
+ if ((set_visible == null) && (get_visible == null))
+ return null;
+
+ string visibility;
+ StringBuilder buf = new StringBuilder ();
+ if (get_visible != null && (set_visible == null || (set_visible != null && get_visible == set_visible)))
+ buf.Append (visibility = get_visible);
+ else if (set_visible != null && get_visible == null)
+ buf.Append (visibility = set_visible);
+ else
+ buf.Append (visibility = "public");
+
+ // Pick an accessor to use for static/virtual/override/etc. checks.
+ method = property.SetMethod;
+ if (method == null)
+ method = property.GetMethod;
+
+ string modifiers = String.Empty;
+ if (method.IsStatic) modifiers += " static";
+ if (method.IsVirtual && !method.IsAbstract)
+ {
+ if ((method.Attributes & MethodAttributes.NewSlot) != 0)
+ modifiers += " virtual";
+ else
+ modifiers += " override";
+ }
+ TypeDefinition declDef = (TypeDefinition)method.DeclaringType;
+ if (method.IsAbstract && !declDef.IsInterface)
+ modifiers += " abstract";
+ if (method.IsFinal)
+ modifiers += " sealed";
+ if (modifiers == " virtual sealed")
+ modifiers = "";
+ buf.Append (modifiers).Append (' ');
+
+ buf.Append (GetTypeName (property.PropertyType, new DynamicParserContext (property))).Append (' ');
+
+ IEnumerable<MemberReference> defs = property.DeclaringType.GetDefaultMembers ();
+ string name = property.Name;
+ foreach (MemberReference mi in defs)
+ {
+ if (mi == property)
+ {
+ name = "this";
+ break;
+ }
+ }
+ buf.Append (name == "this" ? name : DocUtils.GetPropertyName (property));
+
+ if (property.Parameters.Count != 0)
+ {
+ AppendParameters (buf, method, property.Parameters, '[', ']');
+ }
+
+ buf.Append (" {");
+ if (get_visible != null)
+ {
+ if (get_visible != visibility)
+ buf.Append (' ').Append (get_visible);
+ buf.Append (" get;");
+ }
+ if (set_visible != null)
+ {
+ if (set_visible != visibility)
+ buf.Append (' ').Append (set_visible);
+ buf.Append (" set;");
+ }
+ buf.Append (" }");
+
+ return buf[0] != ' ' ? buf.ToString () : buf.ToString (1, buf.Length - 1);
+ }
+
+ protected override string GetFieldDeclaration (FieldDefinition field)
+ {
+ TypeDefinition declType = (TypeDefinition)field.DeclaringType;
+ if (declType.IsEnum && field.Name == "value__")
+ return null; // This member of enums aren't documented.
+
+ StringBuilder buf = new StringBuilder ();
+ AppendFieldVisibility (buf, field);
+ if (buf.Length == 0)
+ return null;
+
+ if (declType.IsEnum)
+ return field.Name;
+
+ if (field.IsStatic && !field.IsLiteral)
+ buf.Append (" static");
+ if (field.IsInitOnly)
+ buf.Append (" readonly");
+ if (field.IsLiteral)
+ buf.Append (" const");
+
+ buf.Append (' ').Append (GetTypeName (field.FieldType, new DynamicParserContext (field))).Append (' ');
+ buf.Append (field.Name);
+ AppendFieldValue (buf, field);
+ buf.Append (';');
+
+ return buf.ToString ();
+ }
+
+ static StringBuilder AppendFieldVisibility (StringBuilder buf, FieldDefinition field)
+ {
+ if (field.IsPublic)
+ return buf.Append ("public");
+ if (field.IsFamily || field.IsFamilyOrAssembly)
+ return buf.Append ("protected");
+ return buf;
+ }
+
+ static StringBuilder AppendFieldValue (StringBuilder buf, FieldDefinition field)
+ {
+ // enums have a value__ field, which we ignore
+ if (((TypeDefinition)field.DeclaringType).IsEnum ||
+ field.DeclaringType.IsGenericType ())
+ return buf;
+ if (field.HasConstant && field.IsLiteral)
+ {
+ object val = null;
+ try
+ {
+ val = field.Constant;
+ }
+ catch
+ {
+ return buf;
+ }
+ if (val == null)
+ buf.Append (" = ").Append ("null");
+ else if (val is Enum)
+ buf.Append (" = ").Append (val.ToString ());
+ else if (val is IFormattable)
+ {
+ string value = ((IFormattable)val).ToString (null, CultureInfo.InvariantCulture);
+ if (val is string)
+ value = "\"" + value + "\"";
+ buf.Append (" = ").Append (value);
+ }
+ }
+ return buf;
+ }
+
+ protected override string GetEventDeclaration (EventDefinition e)
+ {
+ StringBuilder buf = new StringBuilder ();
+ if (AppendVisibility (buf, e.AddMethod).Length == 0)
+ {
+ return null;
+ }
+
+ AppendModifiers (buf, e.AddMethod);
+
+ buf.Append (" event ");
+ buf.Append (GetTypeName (e.EventType, new DynamicParserContext (e.AddMethod.Parameters[0]))).Append (' ');
+ buf.Append (e.Name).Append (';');
+
+ return buf.ToString ();
+ }
+ }
+} \ No newline at end of file
diff --git a/mdoc/Mono.Documentation/Updater/Formatters/CSharpMemberFormatter.cs b/mdoc/Mono.Documentation/Updater/Formatters/CSharpMemberFormatter.cs
new file mode 100644
index 00000000..56129c7b
--- /dev/null
+++ b/mdoc/Mono.Documentation/Updater/Formatters/CSharpMemberFormatter.cs
@@ -0,0 +1,14 @@
+using System.Text;
+
+using Mono.Cecil;
+
+namespace Mono.Documentation.Updater
+{
+ public class CSharpMemberFormatter : CSharpFullMemberFormatter
+ {
+ protected override StringBuilder AppendNamespace (StringBuilder buf, TypeReference type)
+ {
+ return buf;
+ }
+ }
+} \ No newline at end of file
diff --git a/mdoc/Mono.Documentation/Updater/Formatters/CSharpNativeTypeMemberFormatter.cs b/mdoc/Mono.Documentation/Updater/Formatters/CSharpNativeTypeMemberFormatter.cs
new file mode 100644
index 00000000..9cd2ee9b
--- /dev/null
+++ b/mdoc/Mono.Documentation/Updater/Formatters/CSharpNativeTypeMemberFormatter.cs
@@ -0,0 +1,26 @@
+namespace Mono.Documentation.Updater
+{
+ class CSharpNativeTypeMemberFormatter : CSharpFullMemberFormatter
+ {
+ protected override string GetCSharpType (string t)
+ {
+ string moddedType = base.GetCSharpType (t);
+
+ switch (moddedType)
+ {
+ case "int": return "nint";
+ case "uint":
+ return "nuint";
+ case "float":
+ return "nfloat";
+ case "System.Drawing.SizeF":
+ return "CoreGraphics.CGSize";
+ case "System.Drawing.PointF":
+ return "CoreGraphics.CGPoint";
+ case "System.Drawing.RectangleF":
+ return "CoreGraphics.CGPoint";
+ }
+ return null;
+ }
+ }
+} \ No newline at end of file
diff --git a/mdoc/Mono.Documentation/Updater/Formatters/DefaultAttributeValueFormatter.cs b/mdoc/Mono.Documentation/Updater/Formatters/DefaultAttributeValueFormatter.cs
new file mode 100644
index 00000000..dac130d2
--- /dev/null
+++ b/mdoc/Mono.Documentation/Updater/Formatters/DefaultAttributeValueFormatter.cs
@@ -0,0 +1,13 @@
+namespace Mono.Documentation.Updater
+{
+ /// <summary>The final value formatter in the pipeline ... if no other formatter formats the value,
+ /// then this one will serve as the default implementation.</summary>
+ class DefaultAttributeValueFormatter : AttributeValueFormatter
+ {
+ public override bool TryFormatValue (object v, ResolvedTypeInfo type, out string returnvalue)
+ {
+ returnvalue = "(" + MDocUpdater.GetDocTypeFullName (type.Reference) + ") " + v.ToString ();
+ return true;
+ }
+ }
+} \ No newline at end of file
diff --git a/mdoc/Mono.Documentation/Updater/Formatters/DocIdFormatter.cs b/mdoc/Mono.Documentation/Updater/Formatters/DocIdFormatter.cs
new file mode 100644
index 00000000..7169ab93
--- /dev/null
+++ b/mdoc/Mono.Documentation/Updater/Formatters/DocIdFormatter.cs
@@ -0,0 +1,23 @@
+
+using Mono.Cecil;
+using Mono.Cecil.Rocks;
+
+namespace Mono.Documentation.Updater
+{
+ class DocIdFormatter : MemberFormatter
+ {
+ public override string Language
+ {
+ get { return "DocId"; }
+ }
+
+ public override string GetDeclaration (TypeReference tref)
+ {
+ return DocCommentId.GetDocCommentId (tref.Resolve ());
+ }
+ public override string GetDeclaration (MemberReference mreference)
+ {
+ return DocCommentId.GetDocCommentId (mreference.Resolve ());
+ }
+ }
+} \ No newline at end of file
diff --git a/mdoc/Mono.Documentation/Updater/Formatters/DocTypeFullMemberFormatter.cs b/mdoc/Mono.Documentation/Updater/Formatters/DocTypeFullMemberFormatter.cs
new file mode 100644
index 00000000..087b9bb8
--- /dev/null
+++ b/mdoc/Mono.Documentation/Updater/Formatters/DocTypeFullMemberFormatter.cs
@@ -0,0 +1,12 @@
+namespace Mono.Documentation.Updater
+{
+ class DocTypeFullMemberFormatter : MemberFormatter
+ {
+ public static readonly MemberFormatter Default = new DocTypeFullMemberFormatter ();
+
+ protected override char NestedTypeSeparator
+ {
+ get { return '+'; }
+ }
+ }
+} \ No newline at end of file
diff --git a/mdoc/Mono.Documentation/Updater/Formatters/DocTypeMemberFormatter.cs b/mdoc/Mono.Documentation/Updater/Formatters/DocTypeMemberFormatter.cs
new file mode 100644
index 00000000..d87a0604
--- /dev/null
+++ b/mdoc/Mono.Documentation/Updater/Formatters/DocTypeMemberFormatter.cs
@@ -0,0 +1,14 @@
+using System.Text;
+
+using Mono.Cecil;
+
+namespace Mono.Documentation.Updater
+{
+ class DocTypeMemberFormatter : DocTypeFullMemberFormatter
+ {
+ protected override StringBuilder AppendNamespace (StringBuilder buf, TypeReference type)
+ {
+ return buf;
+ }
+ }
+} \ No newline at end of file
diff --git a/mdoc/Mono.Documentation/Updater/Formatters/FileNameMemberFormatter.cs b/mdoc/Mono.Documentation/Updater/Formatters/FileNameMemberFormatter.cs
new file mode 100644
index 00000000..8fb7a54b
--- /dev/null
+++ b/mdoc/Mono.Documentation/Updater/Formatters/FileNameMemberFormatter.cs
@@ -0,0 +1,19 @@
+using System.Text;
+
+using Mono.Cecil;
+
+namespace Mono.Documentation.Updater
+{
+ class FileNameMemberFormatter : SlashDocMemberFormatter
+ {
+ protected override StringBuilder AppendNamespace (StringBuilder buf, TypeReference type)
+ {
+ return buf;
+ }
+
+ protected override char NestedTypeSeparator
+ {
+ get { return '+'; }
+ }
+ }
+} \ No newline at end of file
diff --git a/mdoc/Mono.Documentation/Updater/Formatters/ILFullMemberFormatter.cs b/mdoc/Mono.Documentation/Updater/Formatters/ILFullMemberFormatter.cs
new file mode 100644
index 00000000..bd21c204
--- /dev/null
+++ b/mdoc/Mono.Documentation/Updater/Formatters/ILFullMemberFormatter.cs
@@ -0,0 +1,573 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Text;
+
+using Mono.Cecil;
+
+using Mono.Documentation.Util;
+
+namespace Mono.Documentation.Updater
+{
+ public class ILFullMemberFormatter : MemberFormatter
+ {
+
+ public override string Language
+ {
+ get { return "ILAsm"; }
+ }
+
+ protected override char NestedTypeSeparator
+ {
+ get
+ {
+ return '/';
+ }
+ }
+
+ protected override StringBuilder AppendNamespace (StringBuilder buf, TypeReference type)
+ {
+ if (GetBuiltinType (type.FullName) != null)
+ return buf;
+ string ns = DocUtils.GetNamespace (type);
+ if (ns != null && ns.Length > 0)
+ {
+ if (type.IsValueType)
+ buf.Append ("valuetype ");
+ else
+ buf.Append ("class ");
+ buf.Append (ns).Append ('.');
+ }
+ return buf;
+ }
+
+ protected static string GetBuiltinType (string t)
+ {
+ switch (t)
+ {
+ case "System.Byte": return "unsigned int8";
+ case "System.SByte": return "int8";
+ case "System.Int16": return "int16";
+ case "System.Int32": return "int32";
+ case "System.Int64": return "int64";
+ case "System.IntPtr": return "native int";
+
+ case "System.UInt16": return "unsigned int16";
+ case "System.UInt32": return "unsigned int32";
+ case "System.UInt64": return "unsigned int64";
+ case "System.UIntPtr": return "native unsigned int";
+
+ case "System.Single": return "float32";
+ case "System.Double": return "float64";
+ case "System.Boolean": return "bool";
+ case "System.Char": return "char";
+ case "System.Void": return "void";
+ case "System.String": return "string";
+ case "System.Object": return "object";
+ }
+ return null;
+ }
+
+ protected override StringBuilder AppendTypeName (StringBuilder buf, string typename)
+ {
+ return buf.Append (typename);
+ }
+
+ protected override StringBuilder AppendTypeName (StringBuilder buf, TypeReference type, DynamicParserContext context)
+ {
+ if (type is GenericParameter)
+ {
+ AppendGenericParameterConstraints (buf, (GenericParameter)type).Append (type.Name);
+ return buf;
+ }
+
+ string s = GetBuiltinType (type.FullName);
+ if (s != null)
+ {
+ return buf.Append (s);
+ }
+ return base.AppendTypeName (buf, type, context);
+ }
+
+ private StringBuilder AppendGenericParameterConstraints (StringBuilder buf, GenericParameter type)
+ {
+ if (MemberFormatterState != MemberFormatterState.WithinGenericTypeParameters)
+ {
+ return buf.Append (type.Owner is TypeReference ? "!" : "!!");
+ }
+ GenericParameterAttributes attrs = type.Attributes;
+ if ((attrs & GenericParameterAttributes.ReferenceTypeConstraint) != 0)
+ buf.Append ("class ");
+ if ((attrs & GenericParameterAttributes.NotNullableValueTypeConstraint) != 0)
+ buf.Append ("struct ");
+ if ((attrs & GenericParameterAttributes.DefaultConstructorConstraint) != 0)
+ buf.Append (".ctor ");
+ IList<TypeReference> constraints = type.Constraints;
+ MemberFormatterState = 0;
+ if (constraints.Count > 0)
+ {
+ var full = new ILFullMemberFormatter ();
+ buf.Append ("(").Append (full.GetName (constraints[0]));
+ for (int i = 1; i < constraints.Count; ++i)
+ {
+ buf.Append (", ").Append (full.GetName (constraints[i]));
+ }
+ buf.Append (") ");
+ }
+ MemberFormatterState = MemberFormatterState.WithinGenericTypeParameters;
+
+ if ((attrs & GenericParameterAttributes.Covariant) != 0)
+ buf.Append ("+ ");
+ if ((attrs & GenericParameterAttributes.Contravariant) != 0)
+ buf.Append ("- ");
+ return buf;
+ }
+
+ protected override string GetTypeDeclaration (TypeDefinition type)
+ {
+ string visibility = GetTypeVisibility (type.Attributes);
+ if (visibility == null)
+ return null;
+
+ StringBuilder buf = new StringBuilder ();
+
+ buf.Append (".class ");
+ if (type.IsNested)
+ buf.Append ("nested ");
+ buf.Append (visibility).Append (" ");
+ if (type.IsInterface)
+ buf.Append ("interface ");
+ if (type.IsSequentialLayout)
+ buf.Append ("sequential ");
+ if (type.IsAutoLayout)
+ buf.Append ("auto ");
+ if (type.IsAnsiClass)
+ buf.Append ("ansi ");
+ if (type.IsAbstract)
+ buf.Append ("abstract ");
+ if (type.IsSerializable)
+ buf.Append ("serializable ");
+ if (type.IsSealed)
+ buf.Append ("sealed ");
+ if (type.IsBeforeFieldInit)
+ buf.Append ("beforefieldinit ");
+ var state = MemberFormatterState;
+ MemberFormatterState = MemberFormatterState.WithinGenericTypeParameters;
+ buf.Append (GetName (type));
+ MemberFormatterState = state;
+ var full = new ILFullMemberFormatter ();
+ if (type.BaseType != null)
+ {
+ buf.Append (" extends ");
+ if (type.BaseType.FullName == "System.Object")
+ buf.Append ("System.Object");
+ else
+ buf.Append (full.GetName (type.BaseType).Substring ("class ".Length));
+ }
+ bool first = true;
+ foreach (var name in type.Interfaces.Where (i => MDocUpdater.IsPublic (i.InterfaceType.Resolve ()))
+ .Select (i => full.GetName (i.InterfaceType))
+ .OrderBy (n => n))
+ {
+ if (first)
+ {
+ buf.Append (" implements ");
+ first = false;
+ }
+ else
+ {
+ buf.Append (", ");
+ }
+ buf.Append (name);
+ }
+
+ return buf.ToString ();
+ }
+
+ protected override StringBuilder AppendGenericType (StringBuilder buf, TypeReference type, DynamicParserContext context)
+ {
+ List<TypeReference> decls = DocUtils.GetDeclaringTypes (
+ type is GenericInstanceType ? type.GetElementType () : type);
+ bool first = true;
+ foreach (var decl in decls)
+ {
+ TypeReference declDef = decl.Resolve () ?? decl;
+ if (!first)
+ {
+ buf.Append (NestedTypeSeparator);
+ }
+ first = false;
+ AppendTypeName (buf, declDef, context);
+ }
+ buf.Append ('<');
+ first = true;
+ foreach (TypeReference arg in GetGenericArguments (type))
+ {
+ if (!first)
+ buf.Append (", ");
+ first = false;
+ _AppendTypeName (buf, arg, context);
+ }
+ buf.Append ('>');
+ return buf;
+ }
+
+ static string GetTypeVisibility (TypeAttributes ta)
+ {
+ switch (ta & TypeAttributes.VisibilityMask)
+ {
+ case TypeAttributes.Public:
+ case TypeAttributes.NestedPublic:
+ return "public";
+
+ case TypeAttributes.NestedFamily:
+ case TypeAttributes.NestedFamORAssem:
+ return "protected";
+
+ default:
+ return null;
+ }
+ }
+
+ protected override string GetConstructorDeclaration (MethodDefinition constructor)
+ {
+ return GetMethodDeclaration (constructor);
+ }
+
+ protected override string GetMethodDeclaration (MethodDefinition method)
+ {
+ if (method.IsPrivate && !DocUtils.IsExplicitlyImplemented (method))
+ return null;
+
+ var buf = new StringBuilder ();
+ buf.Append (".method ");
+ AppendVisibility (buf, method);
+ if (method.IsStatic)
+ buf.Append ("static ");
+ if (method.IsHideBySig)
+ buf.Append ("hidebysig ");
+ if (method.IsPInvokeImpl)
+ {
+ var info = method.PInvokeInfo;
+ buf.Append ("pinvokeimpl (\"")
+ .Append (info.Module.Name)
+ .Append ("\" as \"")
+ .Append (info.EntryPoint)
+ .Append ("\"");
+ if (info.IsCharSetAuto)
+ buf.Append (" auto");
+ if (info.IsCharSetUnicode)
+ buf.Append (" unicode");
+ if (info.IsCharSetAnsi)
+ buf.Append (" ansi");
+ if (info.IsCallConvCdecl)
+ buf.Append (" cdecl");
+ if (info.IsCallConvStdCall)
+ buf.Append (" stdcall");
+ if (info.IsCallConvWinapi)
+ buf.Append (" winapi");
+ if (info.IsCallConvThiscall)
+ buf.Append (" thiscall");
+ if (info.SupportsLastError)
+ buf.Append (" lasterr");
+ buf.Append (")");
+ }
+ if (method.IsSpecialName)
+ buf.Append ("specialname ");
+ if (method.IsRuntimeSpecialName)
+ buf.Append ("rtspecialname ");
+ if (method.IsNewSlot)
+ buf.Append ("newslot ");
+ if (method.IsVirtual)
+ buf.Append ("virtual ");
+ if (!method.IsStatic)
+ buf.Append ("instance ");
+ _AppendTypeName (buf, method.ReturnType, new DynamicParserContext (method.MethodReturnType));
+ buf.Append (' ')
+ .Append (method.Name);
+ if (method.IsGenericMethod ())
+ {
+ var state = MemberFormatterState;
+ MemberFormatterState = MemberFormatterState.WithinGenericTypeParameters;
+ IList<GenericParameter> args = method.GenericParameters;
+ if (args.Count > 0)
+ {
+ buf.Append ("<");
+ _AppendTypeName (buf, args[0], null);
+ for (int i = 1; i < args.Count; ++i)
+ _AppendTypeName (buf.Append (", "), args[i], null);
+ buf.Append (">");
+ }
+ MemberFormatterState = state;
+ }
+
+ buf.Append ('(');
+ bool first = true;
+ for (int i = 0; i < method.Parameters.Count; ++i)
+ {
+ var param = method.Parameters[i];
+ if (!first)
+ buf.Append (", ");
+ first = false;
+
+ if (param.IsOut) buf.Append ("[out] ");
+ else if (param.IsIn) buf.Append ("[in]");
+
+ _AppendTypeName (buf, param.ParameterType, new DynamicParserContext (param));
+ if (param.ParameterType.IsByReference) buf.Append ("&");
+ buf.Append (' ');
+ buf.Append (param.Name);
+ }
+ buf.Append (')');
+ if (method.IsIL)
+ buf.Append (" cil");
+ if (method.IsRuntime)
+ buf.Append (" runtime");
+ if (method.IsManaged)
+ buf.Append (" managed");
+
+ return buf.ToString ();
+ }
+
+ protected override StringBuilder AppendMethodName (StringBuilder buf, MethodDefinition method)
+ {
+ if (DocUtils.IsExplicitlyImplemented (method))
+ {
+ TypeReference iface;
+ MethodReference ifaceMethod;
+ DocUtils.GetInfoForExplicitlyImplementedMethod (method, out iface, out ifaceMethod);
+ return buf.Append (new CSharpMemberFormatter ().GetName (iface))
+ .Append ('.')
+ .Append (ifaceMethod.Name);
+ }
+ return base.AppendMethodName (buf, method);
+ }
+
+ protected override string RefTypeModifier
+ {
+ get { return ""; }
+ }
+
+ protected override StringBuilder AppendVisibility (StringBuilder buf, MethodDefinition method)
+ {
+ if (method.IsPublic)
+ return buf.Append ("public ");
+ if (method.IsFamilyAndAssembly)
+ return buf.Append ("familyandassembly");
+ if (method.IsFamilyOrAssembly)
+ return buf.Append ("familyorassembly");
+ if (method.IsFamily)
+ return buf.Append ("family");
+ return buf;
+ }
+
+ protected override StringBuilder AppendModifiers (StringBuilder buf, MethodDefinition method)
+ {
+ string modifiers = String.Empty;
+ if (method.IsStatic) modifiers += " static";
+ if (method.IsVirtual && !method.IsAbstract)
+ {
+ if ((method.Attributes & MethodAttributes.NewSlot) != 0) modifiers += " virtual";
+ else modifiers += " override";
+ }
+ TypeDefinition declType = (TypeDefinition)method.DeclaringType;
+ if (method.IsAbstract && !declType.IsInterface) modifiers += " abstract";
+ if (method.IsFinal) modifiers += " sealed";
+ if (modifiers == " virtual sealed") modifiers = "";
+
+ return buf.Append (modifiers);
+ }
+
+ protected override StringBuilder AppendGenericMethod (StringBuilder buf, MethodDefinition method)
+ {
+ if (method.IsGenericMethod ())
+ {
+ IList<GenericParameter> args = method.GenericParameters;
+ if (args.Count > 0)
+ {
+ buf.Append ("<");
+ buf.Append (args[0].Name);
+ for (int i = 1; i < args.Count; ++i)
+ buf.Append (",").Append (args[i].Name);
+ buf.Append (">");
+ }
+ }
+ return buf;
+ }
+
+ protected override StringBuilder AppendParameters (StringBuilder buf, MethodDefinition method, IList<ParameterDefinition> parameters)
+ {
+ return AppendParameters (buf, method, parameters, '(', ')');
+ }
+
+ private StringBuilder AppendParameters (StringBuilder buf, MethodDefinition method, IList<ParameterDefinition> parameters, char begin, char end)
+ {
+ buf.Append (begin);
+
+ if (parameters.Count > 0)
+ {
+ if (DocUtils.IsExtensionMethod (method))
+ buf.Append ("this ");
+ AppendParameter (buf, parameters[0]);
+ for (int i = 1; i < parameters.Count; ++i)
+ {
+ buf.Append (", ");
+ AppendParameter (buf, parameters[i]);
+ }
+ }
+
+ return buf.Append (end);
+ }
+
+ private StringBuilder AppendParameter (StringBuilder buf, ParameterDefinition parameter)
+ {
+ if (parameter.ParameterType is ByReferenceType)
+ {
+ if (parameter.IsOut)
+ buf.Append ("out ");
+ else
+ buf.Append ("ref ");
+ }
+ buf.Append (GetName (parameter.ParameterType)).Append (" ");
+ return buf.Append (parameter.Name);
+ }
+
+ protected override string GetPropertyDeclaration (PropertyDefinition property)
+ {
+ MethodDefinition gm = null, sm = null;
+
+ string get_visible = null;
+ if ((gm = property.GetMethod) != null &&
+ (DocUtils.IsExplicitlyImplemented (gm) ||
+ (!gm.IsPrivate && !gm.IsAssembly && !gm.IsFamilyAndAssembly)))
+ get_visible = AppendVisibility (new StringBuilder (), gm).ToString ();
+ string set_visible = null;
+ if ((sm = property.SetMethod) != null &&
+ (DocUtils.IsExplicitlyImplemented (sm) ||
+ (!sm.IsPrivate && !sm.IsAssembly && !sm.IsFamilyAndAssembly)))
+ set_visible = AppendVisibility (new StringBuilder (), sm).ToString ();
+
+ if ((set_visible == null) && (get_visible == null))
+ return null;
+
+ StringBuilder buf = new StringBuilder ()
+ .Append (".property ");
+ if (!(gm ?? sm).IsStatic)
+ buf.Append ("instance ");
+ _AppendTypeName (buf, property.PropertyType, new DynamicParserContext (property));
+ buf.Append (' ').Append (property.Name);
+ if (!property.HasParameters || property.Parameters.Count == 0)
+ return buf.ToString ();
+
+ buf.Append ('(');
+ bool first = true;
+ foreach (ParameterDefinition p in property.Parameters)
+ {
+ if (!first)
+ buf.Append (", ");
+ first = false;
+ _AppendTypeName (buf, p.ParameterType, new DynamicParserContext (p));
+ }
+ buf.Append (')');
+
+ return buf.ToString ();
+ }
+
+ protected override string GetFieldDeclaration (FieldDefinition field)
+ {
+ TypeDefinition declType = (TypeDefinition)field.DeclaringType;
+ if (declType.IsEnum && field.Name == "value__")
+ return null; // This member of enums aren't documented.
+
+ StringBuilder buf = new StringBuilder ();
+ AppendFieldVisibility (buf, field);
+ if (buf.Length == 0)
+ return null;
+
+ buf.Insert (0, ".field ");
+
+ if (field.IsStatic)
+ buf.Append ("static ");
+ if (field.IsInitOnly)
+ buf.Append ("initonly ");
+ if (field.IsLiteral)
+ buf.Append ("literal ");
+ _AppendTypeName (buf, field.FieldType, new DynamicParserContext (field));
+ buf.Append (' ').Append (field.Name);
+ AppendFieldValue (buf, field);
+
+ return buf.ToString ();
+ }
+
+ static StringBuilder AppendFieldVisibility (StringBuilder buf, FieldDefinition field)
+ {
+ if (field.IsPublic)
+ return buf.Append ("public ");
+ if (field.IsFamilyAndAssembly)
+ return buf.Append ("familyandassembly ");
+ if (field.IsFamilyOrAssembly)
+ return buf.Append ("familyorassembly ");
+ if (field.IsFamily)
+ return buf.Append ("family ");
+ return buf;
+ }
+
+ static StringBuilder AppendFieldValue (StringBuilder buf, FieldDefinition field)
+ {
+ // enums have a value__ field, which we ignore
+ if (field.DeclaringType.IsGenericType ())
+ return buf;
+ if (field.HasConstant && field.IsLiteral)
+ {
+ object val = null;
+ try
+ {
+ val = field.Constant;
+ }
+ catch
+ {
+ return buf;
+ }
+ if (val == null)
+ buf.Append (" = ").Append ("null");
+ else if (val is Enum)
+ buf.Append (" = ")
+ .Append (GetBuiltinType (field.DeclaringType.GetUnderlyingType ().FullName))
+ .Append ('(')
+ .Append (val.ToString ())
+ .Append (')');
+ else if (val is IFormattable)
+ {
+ string value = ((IFormattable)val).ToString (null, CultureInfo.InvariantCulture);
+ buf.Append (" = ");
+ if (val is string)
+ buf.Append ("\"" + value + "\"");
+ else
+ buf.Append (GetBuiltinType (field.DeclaringType.GetUnderlyingType ().FullName))
+ .Append ('(')
+ .Append (value)
+ .Append (')');
+ }
+ }
+ return buf;
+ }
+
+ protected override string GetEventDeclaration (EventDefinition e)
+ {
+ StringBuilder buf = new StringBuilder ();
+ if (AppendVisibility (buf, e.AddMethod).Length == 0)
+ {
+ return null;
+ }
+
+ buf.Length = 0;
+ buf.Append (".event ")
+ .Append (GetName (e.EventType))
+ .Append (' ')
+ .Append (e.Name);
+
+ return buf.ToString ();
+ }
+ }
+} \ No newline at end of file
diff --git a/mdoc/Mono.Documentation/Updater/Formatters/ILMemberFormatter.cs b/mdoc/Mono.Documentation/Updater/Formatters/ILMemberFormatter.cs
new file mode 100644
index 00000000..b520f9e5
--- /dev/null
+++ b/mdoc/Mono.Documentation/Updater/Formatters/ILMemberFormatter.cs
@@ -0,0 +1,14 @@
+using System.Text;
+
+using Mono.Cecil;
+
+namespace Mono.Documentation.Updater
+{
+ public class ILMemberFormatter : ILFullMemberFormatter
+ {
+ protected override StringBuilder AppendNamespace (StringBuilder buf, TypeReference type)
+ {
+ return buf;
+ }
+ }
+} \ No newline at end of file
diff --git a/mdoc/Mono.Documentation/Updater/Formatters/ILNativeTypeMemberFormatter.cs b/mdoc/Mono.Documentation/Updater/Formatters/ILNativeTypeMemberFormatter.cs
new file mode 100644
index 00000000..70795c3b
--- /dev/null
+++ b/mdoc/Mono.Documentation/Updater/Formatters/ILNativeTypeMemberFormatter.cs
@@ -0,0 +1,10 @@
+namespace Mono.Documentation.Updater
+{
+ class ILNativeTypeMemberFormatter : ILFullMemberFormatter
+ {
+ protected static string _GetBuiltinType (string t)
+ {
+ return null;
+ }
+ }
+} \ No newline at end of file
diff --git a/mdoc/Mono.Documentation/Updater/Formatters/MemberFormatter.cs b/mdoc/Mono.Documentation/Updater/Formatters/MemberFormatter.cs
new file mode 100644
index 00000000..98cd0d4d
--- /dev/null
+++ b/mdoc/Mono.Documentation/Updater/Formatters/MemberFormatter.cs
@@ -0,0 +1,421 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+using Mono.Cecil;
+
+using Mono.Documentation.Util;
+
+namespace Mono.Documentation.Updater
+{
+ public abstract class MemberFormatter
+ {
+
+ public virtual string Language
+ {
+ get { return ""; }
+ }
+
+ public string GetName (MemberReference member)
+ {
+ return GetName (member, null);
+ }
+
+ public virtual string GetName (MemberReference member, DynamicParserContext context)
+ {
+ TypeReference type = member as TypeReference;
+ if (type != null)
+ return GetTypeName (type, context);
+ MethodReference method = member as MethodReference;
+ if (method != null && method.Name == ".ctor") // method.IsConstructor
+ return GetConstructorName (method);
+ if (method != null)
+ return GetMethodName (method);
+ PropertyReference prop = member as PropertyReference;
+ if (prop != null)
+ return GetPropertyName (prop);
+ FieldReference field = member as FieldReference;
+ if (field != null)
+ return GetFieldName (field);
+ EventReference e = member as EventReference;
+ if (e != null)
+ return GetEventName (e);
+ throw new NotSupportedException ("Can't handle: " +
+ (member == null ? "null" : member.GetType ().ToString ()));
+ }
+
+ protected virtual string GetTypeName (TypeReference type)
+ {
+ return GetTypeName (type, null);
+ }
+
+ protected virtual string GetTypeName (TypeReference type, DynamicParserContext context)
+ {
+ if (type == null)
+ throw new ArgumentNullException (nameof (type));
+
+ var typeName = _AppendTypeName (new StringBuilder (type.Name.Length), type, context).ToString ();
+
+ typeName = RemoveMod (typeName);
+
+ return typeName;
+ }
+
+ public static string RemoveMod (string typeName)
+ {
+ if (string.IsNullOrWhiteSpace (typeName)) return typeName;
+
+ // For custom modifiers (modopt/modreq), we are just excising them
+ // via string manipulation for simplicity; since these cannot be
+ // expressed in C#. If finer control is needed in the future, you can
+ // use IModifierType, PointerType, ByReferenceType, etc.
+
+ int modIndex = Math.Max (typeName.LastIndexOf ("modopt(", StringComparison.Ordinal), typeName.LastIndexOf ("modreq(", StringComparison.Ordinal));
+ if (modIndex > 0)
+ {
+ var tname = typeName.Substring (0, modIndex - 1);
+ var parenIndex = typeName.LastIndexOf (')');
+ if (parenIndex == typeName.Length - 2)
+ { // see if there's metadata like a pointer
+ tname += typeName.Last ();
+ }
+ typeName = tname;
+ }
+
+ modIndex = Math.Max (typeName.LastIndexOf ("modopt(", StringComparison.Ordinal), typeName.LastIndexOf ("modreq(", StringComparison.Ordinal));
+ if (modIndex >= 0)
+ return RemoveMod (typeName);
+ else
+ return typeName;
+ }
+
+ protected virtual char[] ArrayDelimeters
+ {
+ get { return new char[] { '[', ']' }; }
+ }
+
+ protected virtual MemberFormatterState MemberFormatterState { get; set; }
+
+ protected StringBuilder _AppendTypeName (StringBuilder buf, TypeReference type, DynamicParserContext context)
+ {
+ if (type is ArrayType)
+ {
+ TypeSpecification spec = type as TypeSpecification;
+ _AppendTypeName (buf, spec != null ? spec.ElementType : type.GetElementType (), context);
+ return AppendArrayModifiers (buf, (ArrayType)type);
+ }
+ if (type is ByReferenceType)
+ {
+ return AppendRefTypeName (buf, type, context);
+ }
+ if (type is PointerType)
+ {
+ return AppendPointerTypeName (buf, type, context);
+ }
+ if (type is GenericParameter)
+ {
+ return AppendTypeName (buf, type, context);
+ }
+ AppendNamespace (buf, type);
+ GenericInstanceType genInst = type as GenericInstanceType;
+ if (type.GenericParameters.Count == 0 &&
+ (genInst == null ? true : genInst.GenericArguments.Count == 0))
+ {
+ return AppendFullTypeName (buf, type, context);
+ }
+ return AppendGenericType (buf, type, context);
+ }
+
+ protected virtual StringBuilder AppendNamespace (StringBuilder buf, TypeReference type)
+ {
+ string ns = DocUtils.GetNamespace (type);
+ if (ns != null && ns.Length > 0)
+ buf.Append (ns).Append ('.');
+ return buf;
+ }
+
+ protected virtual StringBuilder AppendFullTypeName (StringBuilder buf, TypeReference type, DynamicParserContext context)
+ {
+ if (type.DeclaringType != null)
+ AppendFullTypeName (buf, type.DeclaringType, context).Append (NestedTypeSeparator);
+ return AppendTypeName (buf, type, context);
+ }
+
+ protected virtual StringBuilder AppendTypeName (StringBuilder buf, TypeReference type, DynamicParserContext context)
+ {
+ if (context != null)
+ context.TransformIndex++;
+ return AppendTypeName (buf, type.Name);
+ }
+
+ protected virtual StringBuilder AppendTypeName (StringBuilder buf, string typename)
+ {
+ int n = typename.IndexOf ("`");
+ if (n >= 0)
+ return buf.Append (typename.Substring (0, n));
+ return buf.Append (typename);
+ }
+
+ protected virtual StringBuilder AppendArrayModifiers (StringBuilder buf, ArrayType array)
+ {
+ buf.Append (ArrayDelimeters[0]);
+ int rank = array.Rank;
+ if (rank > 1)
+ buf.Append (new string (',', rank - 1));
+ return buf.Append (ArrayDelimeters[1]);
+ }
+
+ protected virtual string RefTypeModifier
+ {
+ get { return "@"; }
+ }
+
+ protected virtual StringBuilder AppendRefTypeName (StringBuilder buf, TypeReference type, DynamicParserContext context)
+ {
+ TypeSpecification spec = type as TypeSpecification;
+ return _AppendTypeName (buf, spec != null ? spec.ElementType : type.GetElementType (), context)
+ .Append (RefTypeModifier);
+ }
+
+ protected virtual string PointerModifier
+ {
+ get { return "*"; }
+ }
+
+ protected virtual StringBuilder AppendPointerTypeName (StringBuilder buf, TypeReference type, DynamicParserContext context)
+ {
+ TypeSpecification spec = type as TypeSpecification;
+ return _AppendTypeName (buf, spec != null ? spec.ElementType : type.GetElementType (), context)
+ .Append (PointerModifier);
+ }
+
+ protected virtual char[] GenericTypeContainer
+ {
+ get { return new char[] { '<', '>' }; }
+ }
+
+ protected virtual char NestedTypeSeparator
+ {
+ get { return '.'; }
+ }
+
+ protected virtual StringBuilder AppendGenericType (StringBuilder buf, TypeReference type, DynamicParserContext context)
+ {
+ List<TypeReference> decls = DocUtils.GetDeclaringTypes (
+ type is GenericInstanceType ? type.GetElementType () : type);
+ List<TypeReference> genArgs = GetGenericArguments (type);
+ int argIdx = 0;
+ int prev = 0;
+ bool insertNested = false;
+ foreach (var decl in decls)
+ {
+ TypeReference declDef = decl.Resolve () ?? decl;
+ if (insertNested)
+ {
+ buf.Append (NestedTypeSeparator);
+ }
+ insertNested = true;
+ AppendTypeName (buf, declDef, context);
+ int ac = DocUtils.GetGenericArgumentCount (declDef);
+ int c = ac - prev;
+ prev = ac;
+ if (c > 0)
+ {
+ buf.Append (GenericTypeContainer[0]);
+ var origState = MemberFormatterState;
+ MemberFormatterState = MemberFormatterState.WithinGenericTypeParameters;
+ _AppendTypeName (buf, genArgs[argIdx++], context);
+ for (int i = 1; i < c; ++i)
+ {
+ _AppendTypeName (buf.Append (","), genArgs[argIdx++], context);
+ }
+ MemberFormatterState = origState;
+ buf.Append (GenericTypeContainer[1]);
+ }
+ }
+ return buf;
+ }
+
+ protected List<TypeReference> GetGenericArguments (TypeReference type)
+ {
+ var args = new List<TypeReference> ();
+ GenericInstanceType inst = type as GenericInstanceType;
+ if (inst != null)
+ args.AddRange (inst.GenericArguments.Cast<TypeReference> ());
+ else
+ args.AddRange (type.GenericParameters.Cast<TypeReference> ());
+ return args;
+ }
+
+ protected virtual StringBuilder AppendGenericTypeConstraints (StringBuilder buf, TypeReference type)
+ {
+ return buf;
+ }
+
+ protected virtual string GetConstructorName (MethodReference constructor)
+ {
+ return constructor.Name;
+ }
+
+ protected virtual string GetMethodName (MethodReference method)
+ {
+ return method.Name;
+ }
+
+ protected virtual string GetPropertyName (PropertyReference property)
+ {
+ return property.Name;
+ }
+
+ protected virtual string GetFieldName (FieldReference field)
+ {
+ return field.Name;
+ }
+
+ protected virtual string GetEventName (EventReference e)
+ {
+ return e.Name;
+ }
+
+ public virtual string GetDeclaration (TypeReference tref)
+ {
+ var typeSpec = tref as TypeSpecification;
+ if (typeSpec != null && typeSpec.Resolve () == null && typeSpec.IsArray && typeSpec.ContainsGenericParameter)
+ {
+ //HACK: there's really no good reference for a generic parameter array, so we're going to use object
+ return "T:System.Array";
+ }
+ TypeDefinition def = tref.Resolve ();
+ if (def != null)
+ return GetTypeDeclaration (def);
+ else
+ return GetTypeName (tref);
+ }
+
+ public virtual string GetDeclaration (MemberReference mreference)
+ {
+ return GetDeclaration (mreference.Resolve ());
+ }
+
+ string GetDeclaration (IMemberDefinition member)
+ {
+ if (member == null)
+ throw new ArgumentNullException ("member");
+ TypeDefinition type = member as TypeDefinition;
+ if (type != null)
+ return GetTypeDeclaration (type);
+ MethodDefinition method = member as MethodDefinition;
+ if (method != null && method.IsConstructor)
+ return GetConstructorDeclaration (method);
+ if (method != null)
+ return GetMethodDeclaration (method);
+ PropertyDefinition prop = member as PropertyDefinition;
+ if (prop != null)
+ return GetPropertyDeclaration (prop);
+ FieldDefinition field = member as FieldDefinition;
+ if (field != null)
+ return GetFieldDeclaration (field);
+ EventDefinition e = member as EventDefinition;
+ if (e != null)
+ return GetEventDeclaration (e);
+ throw new NotSupportedException ("Can't handle: " + member.GetType ().ToString ());
+ }
+
+ protected virtual string GetTypeDeclaration (TypeDefinition type)
+ {
+ if (type == null)
+ throw new ArgumentNullException ("type");
+ StringBuilder buf = new StringBuilder (type.Name.Length);
+ _AppendTypeName (buf, type, null);
+ AppendGenericTypeConstraints (buf, type);
+ return buf.ToString ();
+ }
+
+ protected virtual string GetConstructorDeclaration (MethodDefinition constructor)
+ {
+ return GetConstructorName (constructor);
+ }
+
+ protected virtual string GetMethodDeclaration (MethodDefinition method)
+ {
+ if (method.HasCustomAttributes && method.CustomAttributes.Cast<CustomAttribute> ().Any (
+ ca => ca.GetDeclaringType () == "System.Diagnostics.Contracts.ContractInvariantMethodAttribute"))
+ return null;
+
+ // Special signature for destructors.
+ if (method.Name == "Finalize" && method.Parameters.Count == 0)
+ return GetFinalizerName (method);
+
+ StringBuilder buf = new StringBuilder ();
+
+ AppendVisibility (buf, method);
+ if (buf.Length == 0 &&
+ !(DocUtils.IsExplicitlyImplemented (method) && !method.IsSpecialName))
+ return null;
+
+ AppendModifiers (buf, method);
+
+ if (buf.Length != 0)
+ buf.Append (" ");
+
+ buf.Append (GetTypeName (method.ReturnType, new DynamicParserContext (method.MethodReturnType))).Append (" ");
+
+ AppendMethodName (buf, method);
+ AppendGenericMethod (buf, method).Append (" ");
+ AppendParameters (buf, method, method.Parameters);
+ AppendGenericMethodConstraints (buf, method);
+ return buf.ToString ();
+ }
+
+ protected virtual StringBuilder AppendMethodName (StringBuilder buf, MethodDefinition method)
+ {
+ return buf.Append (method.Name);
+ }
+
+ protected virtual string GetFinalizerName (MethodDefinition method)
+ {
+ return "Finalize";
+ }
+
+ protected virtual StringBuilder AppendVisibility (StringBuilder buf, MethodDefinition method)
+ {
+ return buf;
+ }
+
+ protected virtual StringBuilder AppendModifiers (StringBuilder buf, MethodDefinition method)
+ {
+ return buf;
+ }
+
+ protected virtual StringBuilder AppendGenericMethod (StringBuilder buf, MethodDefinition method)
+ {
+ return buf;
+ }
+
+ protected virtual StringBuilder AppendParameters (StringBuilder buf, MethodDefinition method, IList<ParameterDefinition> parameters)
+ {
+ return buf;
+ }
+
+ protected virtual StringBuilder AppendGenericMethodConstraints (StringBuilder buf, MethodDefinition method)
+ {
+ return buf;
+ }
+
+ protected virtual string GetPropertyDeclaration (PropertyDefinition property)
+ {
+ return GetPropertyName (property);
+ }
+
+ protected virtual string GetFieldDeclaration (FieldDefinition field)
+ {
+ return GetFieldName (field);
+ }
+
+ protected virtual string GetEventDeclaration (EventDefinition e)
+ {
+ return GetEventName (e);
+ }
+ }
+} \ No newline at end of file
diff --git a/mdoc/Mono.Documentation/Updater/Formatters/SlashDocMemberFormatter.cs b/mdoc/Mono.Documentation/Updater/Formatters/SlashDocMemberFormatter.cs
new file mode 100644
index 00000000..05a7c4df
--- /dev/null
+++ b/mdoc/Mono.Documentation/Updater/Formatters/SlashDocMemberFormatter.cs
@@ -0,0 +1,321 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+using Mono.Cecil;
+
+using Mono.Documentation.Util;
+
+namespace Mono.Documentation.Updater
+{
+ class SlashDocMemberFormatter : MemberFormatter
+ {
+
+ protected override char[] GenericTypeContainer
+ {
+ get { return new char[] { '{', '}' }; }
+ }
+
+ private bool AddTypeCount = true;
+
+ private TypeReference genDeclType;
+ private MethodReference genDeclMethod;
+
+ protected override StringBuilder AppendTypeName (StringBuilder buf, TypeReference type, DynamicParserContext context)
+ {
+ if (type is GenericParameter)
+ {
+ int l = buf.Length;
+ if (genDeclType != null)
+ {
+ IList<GenericParameter> genArgs = genDeclType.GenericParameters;
+ for (int i = 0; i < genArgs.Count; ++i)
+ {
+ if (genArgs[i].Name == type.Name)
+ {
+ buf.Append ('`').Append (i);
+ break;
+ }
+ }
+ }
+ if (genDeclMethod != null)
+ {
+ IList<GenericParameter> genArgs = null;
+ if (genDeclMethod.IsGenericMethod ())
+ {
+ genArgs = genDeclMethod.GenericParameters;
+ for (int i = 0; i < genArgs.Count; ++i)
+ {
+ if (genArgs[i].Name == type.Name)
+ {
+ buf.Append ("``").Append (i);
+ break;
+ }
+ }
+ }
+ }
+ if (genDeclType == null && genDeclMethod == null)
+ {
+ // Probably from within an explicitly implemented interface member,
+ // where CSC uses parameter names instead of indices (why?), e.g.
+ // MyList`2.Mono#DocTest#Generic#IFoo{A}#Method``1(`0,``0) instead of
+ // MyList`2.Mono#DocTest#Generic#IFoo{`0}#Method``1(`0,``0).
+ buf.Append (type.Name);
+ }
+ if (buf.Length == l)
+ {
+ throw new Exception (string.Format (
+ "Unable to translate generic parameter {0}; genDeclType={1}, genDeclMethod={2}",
+ type.Name, genDeclType, genDeclMethod));
+ }
+ }
+ else
+ {
+ base.AppendTypeName (buf, type, context);
+ if (AddTypeCount)
+ {
+ int numArgs = type.GenericParameters.Count;
+ if (type.DeclaringType != null)
+ numArgs -= type.GenericParameters.Count;
+ if (numArgs > 0)
+ {
+ buf.Append ('`').Append (numArgs);
+ }
+ }
+ }
+ return buf;
+ }
+
+ protected override StringBuilder AppendArrayModifiers (StringBuilder buf, ArrayType array)
+ {
+ buf.Append (ArrayDelimeters[0]);
+ int rank = array.Rank;
+ if (rank > 1)
+ {
+ buf.Append ("0:");
+ for (int i = 1; i < rank; ++i)
+ {
+ buf.Append (",0:");
+ }
+ }
+ return buf.Append (ArrayDelimeters[1]);
+ }
+
+ protected override StringBuilder AppendGenericType (StringBuilder buf, TypeReference type, DynamicParserContext context)
+ {
+ if (!AddTypeCount)
+ base.AppendGenericType (buf, type, context);
+ else
+ AppendType (buf, type, context);
+ return buf;
+ }
+
+ private StringBuilder AppendType (StringBuilder buf, TypeReference type, DynamicParserContext context)
+ {
+ List<TypeReference> decls = DocUtils.GetDeclaringTypes (type);
+ bool insertNested = false;
+ int prevParamCount = 0;
+ foreach (var decl in decls)
+ {
+ if (insertNested)
+ buf.Append (NestedTypeSeparator);
+ insertNested = true;
+ base.AppendTypeName (buf, decl, context);
+ int argCount = DocUtils.GetGenericArgumentCount (decl);
+ int numArgs = argCount - prevParamCount;
+ prevParamCount = argCount;
+ if (numArgs > 0)
+ buf.Append ('`').Append (numArgs);
+ }
+ return buf;
+ }
+
+ protected override string GetConstructorName (MethodReference constructor)
+ {
+ return GetMethodDefinitionName (constructor, "#ctor");
+ }
+
+ protected override string GetMethodName (MethodReference method)
+ {
+ string name = null;
+ MethodDefinition methodDef = method as MethodDefinition;
+ if (methodDef == null || !DocUtils.IsExplicitlyImplemented (methodDef))
+ name = method.Name;
+ else
+ {
+ TypeReference iface;
+ MethodReference ifaceMethod;
+ DocUtils.GetInfoForExplicitlyImplementedMethod (methodDef, out iface, out ifaceMethod);
+ AddTypeCount = false;
+ name = GetTypeName (iface) + "." + ifaceMethod.Name;
+ AddTypeCount = true;
+ }
+ return GetMethodDefinitionName (method, name);
+ }
+
+ private string GetMethodDefinitionName (MethodReference method, string name)
+ {
+ StringBuilder buf = new StringBuilder ();
+ buf.Append (GetTypeName (method.DeclaringType));
+ buf.Append ('.');
+ buf.Append (name.Replace (".", "#"));
+ if (method.IsGenericMethod ())
+ {
+ IList<GenericParameter> genArgs = method.GenericParameters;
+ if (genArgs.Count > 0)
+ buf.Append ("``").Append (genArgs.Count);
+ }
+ IList<ParameterDefinition> parameters = method.Parameters;
+ try
+ {
+ genDeclType = method.DeclaringType;
+ genDeclMethod = method;
+ AppendParameters (buf, method.DeclaringType.GenericParameters, parameters);
+ }
+ finally
+ {
+ genDeclType = null;
+ genDeclMethod = null;
+ }
+ return buf.ToString ();
+ }
+
+ private StringBuilder AppendParameters (StringBuilder buf, IList<GenericParameter> genArgs, IList<ParameterDefinition> parameters)
+ {
+ if (parameters.Count == 0)
+ return buf;
+
+ buf.Append ('(');
+
+ AppendParameter (buf, genArgs, parameters[0]);
+ for (int i = 1; i < parameters.Count; ++i)
+ {
+ buf.Append (',');
+ AppendParameter (buf, genArgs, parameters[i]);
+ }
+
+ return buf.Append (')');
+ }
+
+ private StringBuilder AppendParameter (StringBuilder buf, IList<GenericParameter> genArgs, ParameterDefinition parameter)
+ {
+ AddTypeCount = false;
+ buf.Append (GetTypeName (parameter.ParameterType));
+ AddTypeCount = true;
+ return buf;
+ }
+
+ protected override string GetPropertyName (PropertyReference property)
+ {
+ string name = null;
+
+ PropertyDefinition propertyDef = property as PropertyDefinition;
+ MethodDefinition method = null;
+ if (propertyDef != null)
+ method = propertyDef.GetMethod ?? propertyDef.SetMethod;
+ if (method != null && !DocUtils.IsExplicitlyImplemented (method))
+ name = property.Name;
+ else
+ {
+ TypeReference iface;
+ MethodReference ifaceMethod;
+ DocUtils.GetInfoForExplicitlyImplementedMethod (method, out iface, out ifaceMethod);
+ AddTypeCount = false;
+ name = string.Join ("#", new string[]{
+ GetTypeName (iface).Replace (".", "#"),
+ DocUtils.GetMember (property.Name)
+ });
+ AddTypeCount = true;
+ }
+
+ StringBuilder buf = new StringBuilder ();
+ buf.Append (GetName (property.DeclaringType));
+ buf.Append ('.');
+ buf.Append (name);
+ IList<ParameterDefinition> parameters = property.Parameters;
+ if (parameters.Count > 0)
+ {
+ genDeclType = property.DeclaringType;
+ buf.Append ('(');
+ IList<GenericParameter> genArgs = property.DeclaringType.GenericParameters;
+ AppendParameter (buf, genArgs, parameters[0]);
+ for (int i = 1; i < parameters.Count; ++i)
+ {
+ buf.Append (',');
+ AppendParameter (buf, genArgs, parameters[i]);
+ }
+ buf.Append (')');
+ genDeclType = null;
+ }
+ return buf.ToString ();
+ }
+
+ protected override string GetFieldName (FieldReference field)
+ {
+ return string.Format ("{0}.{1}",
+ GetName (field.DeclaringType), field.Name);
+ }
+
+ protected override string GetEventName (EventReference e)
+ {
+ return string.Format ("{0}.{1}",
+ GetName (e.DeclaringType), e.Name);
+ }
+
+ protected override string GetTypeDeclaration (TypeDefinition type)
+ {
+ string name = GetName (type);
+ if (type == null)
+ return null;
+ return "T:" + name;
+ }
+
+ protected override string GetConstructorDeclaration (MethodDefinition constructor)
+ {
+ string name = GetName (constructor);
+ if (name == null)
+ return null;
+ return "M:" + name;
+ }
+
+ protected override string GetMethodDeclaration (MethodDefinition method)
+ {
+ string name = GetName (method);
+ if (name == null)
+ return null;
+ if (method.Name == "op_Implicit" || method.Name == "op_Explicit")
+ {
+ genDeclType = method.DeclaringType;
+ genDeclMethod = method;
+ name += "~" + GetName (method.ReturnType);
+ genDeclType = null;
+ genDeclMethod = null;
+ }
+ return "M:" + name;
+ }
+
+ protected override string GetPropertyDeclaration (PropertyDefinition property)
+ {
+ string name = GetName (property);
+ if (name == null)
+ return null;
+ return "P:" + name;
+ }
+
+ protected override string GetFieldDeclaration (FieldDefinition field)
+ {
+ string name = GetName (field);
+ if (name == null)
+ return null;
+ return "F:" + name;
+ }
+
+ protected override string GetEventDeclaration (EventDefinition e)
+ {
+ string name = GetName (e);
+ if (name == null)
+ return null;
+ return "E:" + name;
+ }
+ }
+} \ No newline at end of file
diff --git a/mdoc/Mono.Documentation/Updater/Formatters/StandardFlagsEnumFormatter.cs b/mdoc/Mono.Documentation/Updater/Formatters/StandardFlagsEnumFormatter.cs
new file mode 100644
index 00000000..8b5f65b5
--- /dev/null
+++ b/mdoc/Mono.Documentation/Updater/Formatters/StandardFlagsEnumFormatter.cs
@@ -0,0 +1,34 @@
+using System.Linq;
+
+using Mono.Cecil;
+
+namespace Mono.Documentation.Updater
+{
+ /// <summary>Flags enum formatter that assumes powers of two values.</summary>
+ /// <remarks>As described here: https://msdn.microsoft.com/en-us/library/vstudio/ms229062(v=vs.100).aspx</remarks>
+ class StandardFlagsEnumFormatter : AttributeValueFormatter
+ {
+ public override bool TryFormatValue (object v, ResolvedTypeInfo type, out string returnvalue)
+ {
+ TypeReference valueType = type.Reference;
+ TypeDefinition valueDef = type.Definition;
+ if (valueDef.CustomAttributes.Any (ca => ca.AttributeType.FullName == "System.FlagsAttribute"))
+ {
+
+ string typename = MDocUpdater.GetDocTypeFullName (valueType);
+ var values = MDocUpdater.GetEnumerationValues (valueDef);
+ long c = MDocUpdater.ToInt64 (v);
+ returnvalue = string.Join (" | ",
+ (from i in values.Keys
+ where (c & i) == i && i != 0
+ select typename + "." + values[i])
+ .DefaultIfEmpty (c.ToString ()).ToArray ());
+
+ return true;
+ }
+
+ returnvalue = null;
+ return false;
+ }
+ }
+} \ No newline at end of file
diff --git a/mdoc/Mono.Documentation/Frameworks/AssemblySet.cs b/mdoc/Mono.Documentation/Updater/Frameworks/AssemblySet.cs
index 4d62d3a1..524e39a7 100644
--- a/mdoc/Mono.Documentation/Frameworks/AssemblySet.cs
+++ b/mdoc/Mono.Documentation/Updater/Frameworks/AssemblySet.cs
@@ -5,7 +5,7 @@ using System.IO;
using System.Linq;
using Mono.Cecil;
-namespace Mono.Documentation
+namespace Mono.Documentation.Updater.Frameworks
{
/// <summary>
/// Represents a set of assemblies that we want to document
diff --git a/mdoc/Mono.Documentation/Frameworks/FrameworkEntry.cs b/mdoc/Mono.Documentation/Updater/Frameworks/FrameworkEntry.cs
index c6710f09..c6684d51 100644
--- a/mdoc/Mono.Documentation/Frameworks/FrameworkEntry.cs
+++ b/mdoc/Mono.Documentation/Updater/Frameworks/FrameworkEntry.cs
@@ -4,7 +4,7 @@ using System.Linq;
using Mono.Cecil;
using Mono.Cecil.Rocks;
-namespace Mono.Documentation
+namespace Mono.Documentation.Updater.Frameworks
{
class FrameworkEntry
{
diff --git a/mdoc/Mono.Documentation/Frameworks/FrameworkIndex.cs b/mdoc/Mono.Documentation/Updater/Frameworks/FrameworkIndex.cs
index d8bbf127..e392f585 100644
--- a/mdoc/Mono.Documentation/Frameworks/FrameworkIndex.cs
+++ b/mdoc/Mono.Documentation/Updater/Frameworks/FrameworkIndex.cs
@@ -7,7 +7,7 @@ using System.Xml.Linq;
using Mono.Cecil;
-namespace Mono.Documentation
+namespace Mono.Documentation.Updater.Frameworks
{
class FrameworkIndex
diff --git a/mdoc/Mono.Documentation/Frameworks/FrameworkTypeEntry.cs b/mdoc/Mono.Documentation/Updater/Frameworks/FrameworkTypeEntry.cs
index 3108f11c..67bcee86 100644
--- a/mdoc/Mono.Documentation/Frameworks/FrameworkTypeEntry.cs
+++ b/mdoc/Mono.Documentation/Updater/Frameworks/FrameworkTypeEntry.cs
@@ -3,7 +3,7 @@ using System.Collections.Generic;
using Mono.Cecil;
using Mono.Cecil.Rocks;
-namespace Mono.Documentation
+namespace Mono.Documentation.Updater.Frameworks
{
class FrameworkTypeEntry : IComparable<FrameworkTypeEntry>
{
diff --git a/mdoc/Mono.Documentation/Frameworks/UwpResolver.cs b/mdoc/Mono.Documentation/Updater/Frameworks/UwpResolver.cs
index 40f490ec..4dbbec82 100644
--- a/mdoc/Mono.Documentation/Frameworks/UwpResolver.cs
+++ b/mdoc/Mono.Documentation/Updater/Frameworks/UwpResolver.cs
@@ -4,7 +4,7 @@ using System.IO;
using Microsoft.Win32;
using Mono.Cecil;
-namespace Mono.Documentation.Frameworks
+namespace Mono.Documentation.Updater.Frameworks
{
/// <summary>Mono.Cecil resolver for the windows universal platform</summary>
class UwpResolver : DefaultAssemblyResolver
diff --git a/mdoc/Mono.Documentation/Updater/MemberFormatterState.cs b/mdoc/Mono.Documentation/Updater/MemberFormatterState.cs
new file mode 100644
index 00000000..373c1c94
--- /dev/null
+++ b/mdoc/Mono.Documentation/Updater/MemberFormatterState.cs
@@ -0,0 +1,8 @@
+namespace Mono.Documentation.Updater
+{
+ public enum MemberFormatterState
+ {
+ None,
+ WithinGenericTypeParameters,
+ }
+} \ No newline at end of file
diff --git a/mdoc/Mono.Documentation/Updater/MsxdocDocumentationImporter.cs b/mdoc/Mono.Documentation/Updater/MsxdocDocumentationImporter.cs
new file mode 100644
index 00000000..37dadfa2
--- /dev/null
+++ b/mdoc/Mono.Documentation/Updater/MsxdocDocumentationImporter.cs
@@ -0,0 +1,135 @@
+using System;
+using System.IO;
+using System.Linq;
+using System.Xml;
+
+using Mono.Cecil;
+
+namespace Mono.Documentation.Updater
+{
+ class MsxdocDocumentationImporter : DocumentationImporter
+ {
+
+ XmlDocument slashdocs;
+
+ public MsxdocDocumentationImporter (string file)
+ {
+ try
+ {
+ char oppositeSlash = Path.DirectorySeparatorChar == '/' ? '\\' : '/';
+ if (file.Contains (oppositeSlash))
+ file = file.Replace (oppositeSlash, Path.DirectorySeparatorChar);
+
+ var xml = File.ReadAllText (file);
+
+ // Ensure Unix line endings
+ xml = xml.Replace ("\r", "");
+
+ slashdocs = new XmlDocument ();
+
+ slashdocs.LoadXml (xml);
+ }
+ catch (IOException ex)
+ {
+ Console.WriteLine ($"Importer Error: {ex.Message}");
+ }
+ }
+
+ public override void ImportDocumentation (DocsNodeInfo info)
+ {
+ XmlNode elem = GetDocs (info.Member ?? info.Type);
+
+ if (elem == null)
+ return;
+
+ XmlElement e = info.Node;
+
+ if (elem.SelectSingleNode ("summary") != null)
+ MDocUpdater.ClearElement (e, "summary");
+ if (elem.SelectSingleNode ("remarks") != null)
+ MDocUpdater.ClearElement (e, "remarks");
+ if (elem.SelectSingleNode ("value") != null || elem.SelectSingleNode ("returns") != null)
+ {
+ MDocUpdater.ClearElement (e, "value");
+ MDocUpdater.ClearElement (e, "returns");
+ }
+
+ foreach (XmlNode child in elem.ChildNodes)
+ {
+ switch (child.Name)
+ {
+ case "param":
+ case "typeparam":
+ {
+ XmlAttribute name = child.Attributes["name"];
+ if (name == null)
+ break;
+ XmlElement p2 = (XmlElement)e.SelectSingleNode (child.Name + "[@name='" + name.Value + "']");
+ if (p2 != null)
+ p2.InnerXml = child.InnerXml;
+ break;
+ }
+ // Occasionally XML documentation will use <returns/> on
+ // properties, so let's try to normalize things.
+ case "value":
+ case "returns":
+ {
+ XmlElement v = e.OwnerDocument.CreateElement (info.ReturnIsReturn ? "returns" : "value");
+ v.InnerXml = child.InnerXml;
+ e.AppendChild (v);
+ break;
+ }
+ case "altmember":
+ case "exception":
+ case "permission":
+ {
+ XmlAttribute cref = child.Attributes["cref"] ?? child.Attributes["name"];
+ if (cref == null)
+ break;
+ XmlElement a = (XmlElement)e.SelectSingleNode (child.Name + "[@cref='" + cref.Value + "']");
+ if (a == null)
+ {
+ a = e.OwnerDocument.CreateElement (child.Name);
+ a.SetAttribute ("cref", cref.Value);
+ e.AppendChild (a);
+ }
+ a.InnerXml = child.InnerXml;
+ break;
+ }
+ case "seealso":
+ {
+ XmlAttribute cref = child.Attributes["cref"];
+ if (cref == null)
+ break;
+ XmlElement a = (XmlElement)e.SelectSingleNode ("altmember[@cref='" + cref.Value + "']");
+ if (a == null)
+ {
+ a = e.OwnerDocument.CreateElement ("altmember");
+ a.SetAttribute ("cref", cref.Value);
+ e.AppendChild (a);
+ }
+ break;
+ }
+ default:
+ {
+ bool add = true;
+ if (child.NodeType == XmlNodeType.Element &&
+ e.SelectNodes (child.Name).Cast<XmlElement> ().Any (n => n.OuterXml == child.OuterXml))
+ add = false;
+ if (add)
+ MDocUpdater.CopyNode (child, e);
+ break;
+ }
+ }
+ }
+ }
+
+ private XmlNode GetDocs (MemberReference member)
+ {
+ string slashdocsig = MDocUpdater.slashdocFormatter.GetDeclaration (member);
+ if (slashdocsig != null && slashdocs != null)
+ return slashdocs.SelectSingleNode ("doc/members/member[@name='" + slashdocsig + "']");
+ return null;
+ }
+ }
+} \ No newline at end of file
diff --git a/mdoc/Mono.Documentation/Updater/ResolvedTypeInfo.cs b/mdoc/Mono.Documentation/Updater/ResolvedTypeInfo.cs
new file mode 100644
index 00000000..0db9b6da
--- /dev/null
+++ b/mdoc/Mono.Documentation/Updater/ResolvedTypeInfo.cs
@@ -0,0 +1,29 @@
+
+using Mono.Cecil;
+
+namespace Mono.Documentation.Updater
+{
+ class ResolvedTypeInfo
+ {
+ TypeDefinition typeDef;
+
+ public ResolvedTypeInfo (TypeReference value)
+ {
+ Reference = value;
+ }
+
+ public TypeReference Reference { get; private set; }
+
+ public TypeDefinition Definition
+ {
+ get
+ {
+ if (typeDef == null)
+ {
+ typeDef = Reference.Resolve ();
+ }
+ return typeDef;
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/mdoc/Mono.Documentation/Util/ApiStyle.cs b/mdoc/Mono.Documentation/Util/ApiStyle.cs
new file mode 100644
index 00000000..3a721bf2
--- /dev/null
+++ b/mdoc/Mono.Documentation/Util/ApiStyle.cs
@@ -0,0 +1,8 @@
+namespace Mono.Documentation.Util
+{
+ enum ApiStyle
+ {
+ Classic,
+ Unified
+ }
+} \ No newline at end of file
diff --git a/mdoc/Mono.Documentation/Util/CecilExtensions.cs b/mdoc/Mono.Documentation/Util/CecilExtensions.cs
new file mode 100644
index 00000000..acccd0f7
--- /dev/null
+++ b/mdoc/Mono.Documentation/Util/CecilExtensions.cs
@@ -0,0 +1,120 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+using Mono.Cecil;
+
+namespace Mono.Documentation.Util
+{
+ static class CecilExtensions
+ {
+ public static string GetDeclaringType (this CustomAttribute attribute)
+ {
+ var type = attribute.Constructor.DeclaringType;
+ var typeName = type.FullName;
+
+ string translatedType = NativeTypeManager.GetTranslatedName (type);
+ return translatedType;
+ }
+
+ public static IEnumerable<MemberReference> GetMembers (this TypeDefinition type)
+ {
+ foreach (var c in type.Methods.Where (m => m.IsConstructor))
+ yield return (MemberReference)c;
+ foreach (var e in type.Events)
+ yield return (MemberReference)e;
+ foreach (var f in type.Fields)
+ yield return (MemberReference)f;
+ foreach (var m in type.Methods.Where (m => !m.IsConstructor))
+ yield return (MemberReference)m;
+ foreach (var t in type.NestedTypes)
+ yield return (MemberReference)t;
+ foreach (var p in type.Properties)
+ yield return (MemberReference)p;
+ }
+
+ public static IEnumerable<MemberReference> GetMembers (this TypeDefinition type, string member)
+ {
+ return GetMembers (type).Where (m => m.Name == member);
+ }
+
+ public static MemberReference GetMember (this TypeDefinition type, string member)
+ {
+ return GetMembers (type, member).EnsureZeroOrOne ();
+ }
+
+ static T EnsureZeroOrOne<T> (this IEnumerable<T> source)
+ {
+ if (source.Count () > 1)
+ throw new InvalidOperationException ("too many matches");
+ return source.FirstOrDefault ();
+ }
+
+ public static MethodDefinition GetMethod (this TypeDefinition type, string method)
+ {
+ return type.Methods
+ .Where (m => m.Name == method)
+ .EnsureZeroOrOne ();
+ }
+
+ public static IEnumerable<MemberReference> GetDefaultMembers (this TypeReference type)
+ {
+ TypeDefinition def = type as TypeDefinition;
+ if (def == null)
+ return new MemberReference[0];
+ CustomAttribute defMemberAttr = def.CustomAttributes
+ .FirstOrDefault (c => c.AttributeType.FullName == "System.Reflection.DefaultMemberAttribute");
+ if (defMemberAttr == null)
+ return new MemberReference[0];
+ string name = (string)defMemberAttr.ConstructorArguments[0].Value;
+ return def.Properties
+ .Where (p => p.Name == name)
+ .Select (p => (MemberReference)p);
+ }
+
+ public static IEnumerable<TypeDefinition> GetTypes (this AssemblyDefinition assembly)
+ {
+ return assembly.Modules.SelectMany (md => md.GetAllTypes ());
+ }
+
+ public static TypeDefinition GetType (this AssemblyDefinition assembly, string type)
+ {
+ return GetTypes (assembly)
+ .Where (td => td.FullName == type)
+ .EnsureZeroOrOne ();
+ }
+
+ public static bool IsGenericType (this TypeReference type)
+ {
+ return type.GenericParameters.Count > 0;
+ }
+
+ public static bool IsGenericMethod (this MethodReference method)
+ {
+ return method.GenericParameters.Count > 0;
+ }
+
+ public static TypeReference GetUnderlyingType (this TypeDefinition type)
+ {
+ if (!type.IsEnum)
+ return type;
+ return type.Fields.First (f => f.Name == "value__").FieldType;
+ }
+
+ public static IEnumerable<TypeDefinition> GetAllTypes (this ModuleDefinition self)
+ {
+ return self.Types.SelectMany (t => t.GetAllTypes ());
+ }
+
+ static IEnumerable<TypeDefinition> GetAllTypes (this TypeDefinition self)
+ {
+ yield return self;
+
+ if (!self.HasNestedTypes)
+ yield break;
+
+ foreach (var type in self.NestedTypes.SelectMany (t => t.GetAllTypes ()))
+ yield return type;
+ }
+ }
+} \ No newline at end of file
diff --git a/mdoc/Mono.Documentation/Util/NativeTypeManager.cs b/mdoc/Mono.Documentation/Util/NativeTypeManager.cs
new file mode 100644
index 00000000..6c3e1118
--- /dev/null
+++ b/mdoc/Mono.Documentation/Util/NativeTypeManager.cs
@@ -0,0 +1,125 @@
+using System.Collections.Generic;
+
+using Mono.Cecil;
+
+namespace Mono.Documentation.Util
+{
+ static class NativeTypeManager
+ {
+
+ static Dictionary<string, string> toNativeType = new Dictionary<string, string> (){
+
+ {"int", "nint"},
+ {"Int32", "nint"},
+ {"System.Int32", "System.nint"},
+ {"uint", "nuint"},
+ {"UInt32", "nuint"},
+ {"System.UInt32", "System.nuint"},
+ {"float", "nfloat"},
+ {"Single", "nfloat"},
+ {"System.Single", "System.nfloat"},
+ {"SizeF", "CoreGraphics.CGSize"},
+ {"System.Drawing.SizeF", "CoreGraphics.CGSize"},
+ {"PointF", "CoreGraphics.CGPoint"},
+ {"System.Drawing.PointF", "CoreGraphics.CGPoint"},
+ {"RectangleF", "CoreGraphics.CGRect" },
+ {"System.Drawing.RectangleF", "CoreGraphics.CGRect"}
+ };
+
+ static Dictionary<string, string> fromNativeType = new Dictionary<string, string> (){
+
+ {"nint", "int"},
+ {"System.nint", "System.Int32"},
+ {"nuint", "uint"},
+ {"System.nuint", "System.UInt32"},
+ {"nfloat", "float"},
+ {"System.nfloat", "System.Single"},
+ {"CoreGraphics.CGSize", "System.Drawing.SizeF"},
+ {"CoreGraphics.CGPoint", "System.Drawing.PointF"},
+ {"CoreGraphics.CGRect", "System.Drawing.RectangleF"},
+ {"MonoTouch.CoreGraphics.CGSize", "System.Drawing.SizeF"},
+ {"MonoTouch.CoreGraphics.CGPoint", "System.Drawing.PointF"},
+ {"MonoTouch.CoreGraphics.CGRect", "System.Drawing.RectangleF"}
+ };
+
+ public static string ConvertToNativeType (string typename)
+ {
+ string nvalue;
+
+ bool isOut = false;
+ bool isArray = false;
+ string valueToCompare = StripToComparableType (typename, ref isOut, ref isArray);
+
+ if (toNativeType.TryGetValue (valueToCompare, out nvalue))
+ {
+
+ if (isArray)
+ {
+ nvalue += "[]";
+ }
+ if (isOut)
+ {
+ nvalue += "&";
+ }
+ return nvalue;
+ }
+ return typename;
+ }
+ public static string ConvertFromNativeType (string typename)
+ {
+ string nvalue;
+
+ bool isOut = false;
+ bool isArray = false;
+ string valueToCompare = StripToComparableType (typename, ref isOut, ref isArray);
+
+ if (fromNativeType.TryGetValue (valueToCompare, out nvalue))
+ {
+ if (isArray)
+ {
+ nvalue += "[]";
+ }
+ if (isOut)
+ {
+ nvalue += "&";
+ }
+ return nvalue;
+ }
+ // it wasn't one of the native types ... just return it
+ return typename;
+ }
+
+ static string StripToComparableType (string typename, ref bool isOut, ref bool isArray)
+ {
+ string valueToCompare = typename;
+ if (typename.EndsWith ("[]"))
+ {
+ valueToCompare = typename.Substring (0, typename.Length - 2);
+ isArray = true;
+ }
+ if (typename.EndsWith ("&"))
+ {
+ valueToCompare = typename.Substring (0, typename.Length - 1);
+ isOut = true;
+ }
+ if (typename.Contains ("<"))
+ {
+ // TODO: Need to recursively process generic parameters
+ }
+ return valueToCompare;
+ }
+
+ public static string GetTranslatedName (TypeReference t)
+ {
+ string typename = t.FullName;
+
+ bool isInAssembly = MDocUpdater.IsInAssemblies (t.Module.Name);
+ if (isInAssembly && !typename.StartsWith ("System") && MDocUpdater.HasDroppedNamespace (t))
+ {
+ string nameWithDropped = string.Format ("{0}.{1}", MDocUpdater.droppedNamespace, typename);
+ return nameWithDropped;
+ }
+ return typename;
+ }
+ }
+} \ No newline at end of file
diff --git a/mdoc/Mono.Documentation/assembler.cs b/mdoc/Mono.Documentation/assembler.cs
index c8c89158..97ebe5b1 100644
--- a/mdoc/Mono.Documentation/assembler.cs
+++ b/mdoc/Mono.Documentation/assembler.cs
@@ -17,6 +17,7 @@ using System.IO;
using System.Xml.Linq;
using System.Xml.XPath;
using Monodoc.Ecma;
+using Mono.Documentation.Util;
namespace Mono.Documentation {
diff --git a/mdoc/Mono.Documentation/exceptions.cs b/mdoc/Mono.Documentation/exceptions.cs
index 23b6762a..47738499 100644
--- a/mdoc/Mono.Documentation/exceptions.cs
+++ b/mdoc/Mono.Documentation/exceptions.cs
@@ -32,7 +32,8 @@ using System.Linq;
using Mono.Cecil;
using Mono.Cecil.Cil;
-
+using Mono.Documentation.Updater;
+
namespace Mono.Documentation {
[Flags]
diff --git a/mdoc/Mono.Documentation/monodocer.cs b/mdoc/Mono.Documentation/monodocer.cs
deleted file mode 100644
index b7c8520f..00000000
--- a/mdoc/Mono.Documentation/monodocer.cs
+++ /dev/null
@@ -1,6451 +0,0 @@
-// Updater program for syncing Mono's ECMA-style documentation files
-// with an assembly.
-// By Joshua Tauberer <tauberer@for.net>
-
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using System.Collections.ObjectModel;
-using System.Diagnostics;
-using System.Globalization;
-using System.IO;
-using System.Linq;
-using System.Text;
-using System.Xml;
-using System.Xml.Linq;
-using System.Xml.XPath;
-
-using Mono.Cecil;
-using Mono.Cecil.Rocks;
-using Mono.Options;
-
-using MyXmlNodeList = System.Collections.Generic.List<System.Xml.XmlNode>;
-using StringList = System.Collections.Generic.List<string>;
-using StringToStringMap = System.Collections.Generic.Dictionary<string, string>;
-using StringToXmlNodeMap = System.Collections.Generic.Dictionary<string, System.Xml.XmlNode>;
-
-namespace Mono.Documentation {
- static class NativeTypeManager {
-
- static Dictionary<string, string> toNativeType = new Dictionary<string,string>(){
-
- {"int", "nint"},
- {"Int32", "nint"},
- {"System.Int32", "System.nint"},
- {"uint", "nuint"},
- {"UInt32", "nuint"},
- {"System.UInt32", "System.nuint"},
- {"float", "nfloat"},
- {"Single", "nfloat"},
- {"System.Single", "System.nfloat"},
- {"SizeF", "CoreGraphics.CGSize"},
- {"System.Drawing.SizeF", "CoreGraphics.CGSize"},
- {"PointF", "CoreGraphics.CGPoint"},
- {"System.Drawing.PointF", "CoreGraphics.CGPoint"},
- {"RectangleF", "CoreGraphics.CGRect" },
- {"System.Drawing.RectangleF", "CoreGraphics.CGRect"}
- };
-
- static Dictionary<string, string> fromNativeType = new Dictionary<string,string>(){
-
- {"nint", "int"},
- {"System.nint", "System.Int32"},
- {"nuint", "uint"},
- {"System.nuint", "System.UInt32"},
- {"nfloat", "float"},
- {"System.nfloat", "System.Single"},
- {"CoreGraphics.CGSize", "System.Drawing.SizeF"},
- {"CoreGraphics.CGPoint", "System.Drawing.PointF"},
- {"CoreGraphics.CGRect", "System.Drawing.RectangleF"},
- {"MonoTouch.CoreGraphics.CGSize", "System.Drawing.SizeF"},
- {"MonoTouch.CoreGraphics.CGPoint", "System.Drawing.PointF"},
- {"MonoTouch.CoreGraphics.CGRect", "System.Drawing.RectangleF"}
- };
-
- public static string ConvertToNativeType(string typename) {
- string nvalue;
-
- bool isOut=false;
- bool isArray=false;
- string valueToCompare = StripToComparableType (typename, ref isOut, ref isArray);
-
- if (toNativeType.TryGetValue (valueToCompare, out nvalue)) {
-
- if (isArray) {
- nvalue += "[]";
- }
- if (isOut) {
- nvalue += "&";
- }
- return nvalue;
- }
- return typename;
- }
- public static string ConvertFromNativeType(string typename) {
- string nvalue;
-
- bool isOut=false;
- bool isArray=false;
- string valueToCompare = StripToComparableType (typename, ref isOut, ref isArray);
-
- if (fromNativeType.TryGetValue (valueToCompare, out nvalue)) {
- if (isArray) {
- nvalue += "[]";
- }
- if (isOut) {
- nvalue += "&";
- }
- return nvalue;
- }
- // it wasn't one of the native types ... just return it
- return typename;
- }
-
- static string StripToComparableType (string typename, ref bool isOut, ref bool isArray)
- {
- string valueToCompare = typename;
- if (typename.EndsWith ("[]")) {
- valueToCompare = typename.Substring (0, typename.Length - 2);
- isArray = true;
- }
- if (typename.EndsWith ("&")) {
- valueToCompare = typename.Substring (0, typename.Length - 1);
- isOut = true;
- }
- if (typename.Contains ("<")) {
- // TODO: Need to recursively process generic parameters
- }
- return valueToCompare;
- }
-
- public static string GetTranslatedName(TypeReference t) {
- string typename = t.FullName;
-
- bool isInAssembly = MDocUpdater.IsInAssemblies (t.Module.Name);
- if (isInAssembly && !typename.StartsWith ("System") && MDocUpdater.HasDroppedNamespace (t)) {
- string nameWithDropped = string.Format ("{0}.{1}", MDocUpdater.droppedNamespace, typename);
- return nameWithDropped;
- }
- return typename;
- }
- }
-class MDocUpdater : MDocCommand
-{
- string srcPath;
- List<AssemblySet> assemblies = new List<AssemblySet>();
- StringList globalSearchPaths = new StringList ();
-
- string apistyle = string.Empty;
- bool isClassicRun;
-
- bool delete;
- bool show_exceptions;
- bool no_assembly_versions, ignore_missing_types;
- ExceptionLocations? exceptions;
-
- internal int additions = 0, deletions = 0;
-
- List<DocumentationImporter> importers = new List<DocumentationImporter> ();
-
- DocumentationEnumerator docEnum;
-
- string since;
-
- static readonly MemberFormatter docTypeFormatter = new DocTypeMemberFormatter ();
- static readonly MemberFormatter filenameFormatter = new FileNameMemberFormatter ();
-
- static MemberFormatter[] typeFormatters = new MemberFormatter[]{
- new CSharpMemberFormatter (),
- new ILMemberFormatter (),
- };
-
- static MemberFormatter[] memberFormatters = new MemberFormatter[]{
- new CSharpFullMemberFormatter (),
- new ILFullMemberFormatter (),
- };
-
- internal static readonly MemberFormatter slashdocFormatter = new SlashDocMemberFormatter ();
-
- MyXmlNodeList extensionMethods = new MyXmlNodeList ();
-
- public static string droppedNamespace = string.Empty;
-
- public static bool HasDroppedNamespace(TypeDefinition forType)
- {
- return HasDroppedNamespace(forType.Module);
- }
-
- public static bool HasDroppedNamespace(MemberReference forMember)
- {
- return HasDroppedNamespace(forMember.Module);
- }
-
- public static bool HasDroppedNamespace(AssemblyDefinition forAssembly)
- {
- return HasDroppedNamespace(forAssembly.MainModule);
- }
-
- public static bool HasDroppedNamespace(ModuleDefinition forModule)
- {
- return !string.IsNullOrWhiteSpace (droppedNamespace) && droppedAssemblies.Any(da => da == forModule.Name);
- }
-
- public static bool HasDroppedAnyNamespace ()
- {
- return !string.IsNullOrWhiteSpace (droppedNamespace);
- }
-
- /// <summary>Logic flag to signify that we should list assemblies at the method level, since there are multiple
- /// assemblies for a given type/method.</summary>
- public bool IsMultiAssembly {
- get {
- return apistyle == "classic" || apistyle == "unified" || !string.IsNullOrWhiteSpace(FrameworksPath);
- }
- }
-
- /// <summary>Path which contains multiple folders with assemblies. Each folder contained will represent one framework.</summary>
- string FrameworksPath = string.Empty;
- FrameworkIndex frameworks;
- FrameworkIndex frameworksCache;
-
- static List<string> droppedAssemblies = new List<string>();
-
- public string PreserveTag { get; set; }
- public bool DisableSearchDirectoryRecurse = false;
- public static MDocUpdater Instance { get; private set; }
- public static bool SwitchingToMagicTypes { get; private set; }
-
- public override void Run (IEnumerable<string> args)
- {
- Instance = this;
- show_exceptions = DebugOutput;
- var types = new List<string> ();
- var p = new OptionSet () {
- { "delete",
- "Delete removed members from the XML files.",
- v => delete = v != null },
- { "exceptions:",
- "Document potential exceptions that members can generate. {SOURCES} " +
- "is a comma-separated list of:\n" +
- " asm Method calls in same assembly\n" +
- " depasm Method calls in dependent assemblies\n" +
- " all Record all possible exceptions\n" +
- " added Modifier; only create <exception/>s\n" +
- " for NEW types/members\n" +
- "If nothing is specified, then only exceptions from the member will " +
- "be listed.",
- v => exceptions = ParseExceptionLocations (v) },
- { "f=",
- "Specify a {FLAG} to alter behavior. See later -f* options for available flags.",
- v => {
- switch (v) {
- case "ignore-missing-types":
- ignore_missing_types = true;
- break;
- case "no-assembly-versions":
- no_assembly_versions = true;
- break;
- default:
- throw new Exception ("Unsupported flag `" + v + "'.");
- }
- } },
- { "fignore-missing-types",
- "Do not report an error if a --type=TYPE type\nwas not found.",
- v => ignore_missing_types = v != null },
- { "fno-assembly-versions",
- "Do not generate //AssemblyVersion elements.",
- v => no_assembly_versions = v != null },
- { "i|import=",
- "Import documentation from {FILE}.",
- v => AddImporter (v) },
- { "L|lib=",
- "Check for assembly references in {DIRECTORY}.",
- v => globalSearchPaths.Add (v) },
- { "library=",
- "Ignored for compatibility with update-ecma-xml.",
- v => {} },
- { "o|out=",
- "Root {DIRECTORY} to generate/update documentation.",
- v => srcPath = v },
- { "r=",
- "Search for dependent assemblies in the directory containing {ASSEMBLY}.\n" +
- "(Equivalent to '-L `dirname ASSEMBLY`'.)",
- v => globalSearchPaths.Add (Path.GetDirectoryName (v)) },
- { "since=",
- "Manually specify the assembly {VERSION} that new members were added in.",
- v => since = v },
- { "type=",
- "Only update documentation for {TYPE}.",
- v => types.Add (v) },
- { "dropns=",
- "When processing assembly {ASSEMBLY}, strip off leading namespace {PREFIX}:\n" +
- " e.g. --dropns ASSEMBLY=PREFIX",
- v => {
- var parts = v.Split ('=');
- if (parts.Length != 2) { Console.Error.WriteLine ("Invalid dropns input"); return; }
- var assembly = Path.GetFileName (parts [0].Trim ());
- var prefix = parts [1].Trim();
- droppedAssemblies.Add (assembly);
- droppedNamespace = prefix;
- } },
- { "ntypes",
- "If the new assembly is switching to 'magic types', then this switch should be defined.",
- v => SwitchingToMagicTypes = true },
- { "preserve",
- "Do not delete members that don't exist in the assembly, but rather mark them as preserved.",
- v => PreserveTag = "true" },
- { "api-style=",
- "Denotes the apistyle. Currently, only `classic` and `unified` are supported. `classic` set of assemblies should be run first, immediately followed by 'unified' assemblies with the `dropns` parameter.",
- v => apistyle = v.ToLowerInvariant () },
- { "fx|frameworks=",
- "Configuration XML file, that points to directories which contain libraries that span multiple frameworks.",
- v => FrameworksPath = v },
- { "use-docid",
- "Add 'DocId' to the list of type and member signatures",
- v =>
- {
- typeFormatters = typeFormatters.Union (new MemberFormatter[] { new DocIdFormatter () }).ToArray ();
- memberFormatters = memberFormatters.Union (new MemberFormatter[] { new DocIdFormatter () }).ToArray ();
- } },
- { "disable-searchdir-recurse",
- "Default behavior for adding search directories ('-L') is to recurse them and search in all subdirectories. This disables that",
- v => DisableSearchDirectoryRecurse = true },
- };
- var assemblyPaths = Parse (p, args, "update",
- "[OPTIONS]+ ASSEMBLIES",
- "Create or update documentation from ASSEMBLIES.");
-
- if (!string.IsNullOrWhiteSpace (FrameworksPath)) {
- var configPath = FrameworksPath;
- var frameworksDir = FrameworksPath;
- if (!configPath.EndsWith ("frameworks.xml", StringComparison.InvariantCultureIgnoreCase))
- configPath = Path.Combine (configPath, "frameworks.xml");
- else
- frameworksDir = Path.GetDirectoryName (configPath);
-
- var fxconfig = XDocument.Load (configPath);
- var fxd = fxconfig.Root
- .Elements ("Framework")
- .Select (f => new {
- Name = f.Attribute ("Name").Value,
- Path = Path.Combine(frameworksDir,f.Attribute("Source").Value),
- SearchPaths = f.Elements("assemblySearchPath")
- .Select(a => Path.Combine(frameworksDir, a.Value))
- .ToArray(),
- Imports = f.Elements("import")
- .Select(a => Path.Combine(frameworksDir, a.Value))
- .ToArray()
- })
- .Where (f => Directory.Exists (f.Path));
-
- Func<string, string, IEnumerable<string>> getFiles = (string path, string filters) => {
- return filters
- .Split ('|')
- .SelectMany (v => Directory.GetFiles (path, v));
- };
-
- var sets = fxd.Select (d => new AssemblySet (
- d.Name,
- getFiles (d.Path, "*.dll|*.exe|*.winmd"),
- this.globalSearchPaths.Union (d.SearchPaths),
- d.Imports
- ));
- this.assemblies.AddRange (sets);
- assemblyPaths.AddRange (sets.SelectMany (s => s.AssemblyPaths));
-
- // Create a cache of all frameworks, so we can look up
- // members that may exist only other frameworks before deleting them
- Console.Write ("Creating frameworks cache: ");
- FrameworkIndex cacheIndex = new FrameworkIndex (FrameworksPath);
- string[] prefixesToAvoid = { "get_", "set_", "add_", "remove_", "raise_" };
- foreach (var assemblySet in this.assemblies) {
- using (assemblySet) {
- Console.Write (".");
- foreach (var assembly in assemblySet.Assemblies) {
- var a = cacheIndex.StartProcessingAssembly(assembly, assemblySet.Importers);
- foreach (var type in assembly.GetTypes ()) {
- var t = a.ProcessType (type);
- foreach (var member in type.GetMembers ().Where (m => !prefixesToAvoid.Any (pre => m.Name.StartsWith (pre, StringComparison.Ordinal))))
- t.ProcessMember (member);
- }
- }
- }
- }
- Console.WriteLine($"{Environment.NewLine}done caching.");
- this.frameworksCache = cacheIndex;
- }
- else {
- this.assemblies.Add (new AssemblySet ("Default", assemblyPaths, this.globalSearchPaths, null));
- }
-
- if (assemblyPaths == null)
- return;
- if (assemblyPaths.Count == 0)
- Error ("No assemblies specified.");
-
- if (!DisableSearchDirectoryRecurse) {
- // unless it's been explicitly disabled, let's
- // add all of the subdirectories to the resolver
- // search paths.
- foreach (var assemblySet in this.assemblies)
- assemblySet.RecurseSearchDirectories ();
- }
-
- // validation for the api-style parameter
- if (apistyle == "classic")
- isClassicRun = true;
- else if (apistyle == "unified") {
- if (!droppedAssemblies.Any ())
- Error ("api-style 'unified' must also supply the 'dropns' parameter with at least one assembly and dropped namespace.");
- } else if (!string.IsNullOrWhiteSpace (apistyle))
- Error ("api-style '{0}' is not currently supported", apistyle);
-
- // PARSE BASIC OPTIONS AND LOAD THE ASSEMBLY TO DOCUMENT
-
- if (srcPath == null)
- throw new InvalidOperationException("The --out option is required.");
-
- docEnum = docEnum ?? new DocumentationEnumerator ();
-
- // PERFORM THE UPDATES
- frameworks = new FrameworkIndex (FrameworksPath);
-
- if (types.Count > 0) {
- types.Sort ();
- DoUpdateTypes (srcPath, types, srcPath);
- }
- else
- DoUpdateAssemblies (srcPath, srcPath);
-
- if (!string.IsNullOrWhiteSpace (FrameworksPath))
- frameworks.WriteToDisk (srcPath);
-
- Console.WriteLine("Members Added: {0}, Members Deleted: {1}", additions, deletions);
- }
-
- public static bool IsInAssemblies(string name) {
- return Instance?.assemblies != null ? Instance.assemblies.Any(a => a.Contains(name)) : true;
- }
-
- void AddImporter (string path)
- {
- var importer = GetImporter (path, supportsEcmaDoc:true);
- if (importer != null)
- importers.Add (importer);
- }
-
- internal DocumentationImporter GetImporter (string path, bool supportsEcmaDoc)
- {
- try {
- XmlReader r = new XmlTextReader (path);
- if (r.Read ()) {
- while (r.NodeType != XmlNodeType.Element) {
- if (!r.Read ())
- Error ("Unable to read XML file: {0}.", path);
- }
- if (r.LocalName == "doc") {
- return new MsxdocDocumentationImporter (path);
- }
- else if (r.LocalName == "Libraries") {
- if (!supportsEcmaDoc)
- throw new NotSupportedException ($"Ecma documentation not supported in this mode: {path}");
-
- var ecmadocs = new XmlTextReader (path);
- docEnum = new EcmaDocumentationEnumerator (this, ecmadocs);
- return new EcmaDocumentationImporter (ecmadocs);
- }
- else
- Error ("Unsupported XML format within {0}.", path);
- }
- r.Close ();
- } catch (Exception e) {
- Environment.ExitCode = 1;
- Error ("Could not load XML file: {0}.", e.Message);
- }
- return null;
- }
-
- static ExceptionLocations ParseExceptionLocations (string s)
- {
- ExceptionLocations loc = ExceptionLocations.Member;
- if (s == null)
- return loc;
- foreach (var type in s.Split (',')) {
- switch (type) {
- case "added": loc |= ExceptionLocations.AddedMembers; break;
- case "all": loc |= ExceptionLocations.Assembly | ExceptionLocations.DependentAssemblies; break;
- case "asm": loc |= ExceptionLocations.Assembly; break;
- case "depasm": loc |= ExceptionLocations.DependentAssemblies; break;
- default: throw new NotSupportedException ("Unsupported --exceptions value: " + type);
- }
- }
- return loc;
- }
-
- internal void Warning (string format, params object[] args)
- {
- Message (TraceLevel.Warning, "mdoc: " + format, args);
- }
-
- internal AssemblyDefinition LoadAssembly (string name, IAssemblyResolver assemblyResolver)
- {
- AssemblyDefinition assembly = null;
- try {
- assembly = AssemblyDefinition.ReadAssembly (name, new ReaderParameters { AssemblyResolver = assemblyResolver });
- }
- catch (Exception ex) {
- Warning ($"Unable to load assembly '{name}': {ex.Message}");
- }
-
- return assembly;
- }
-
- private static void WriteXml(XmlElement element, System.IO.TextWriter output) {
- OrderTypeAttributes (element);
- XmlTextWriter writer = new XmlTextWriter(output);
- writer.Formatting = Formatting.Indented;
- writer.Indentation = 2;
- writer.IndentChar = ' ';
- element.WriteTo(writer);
- output.WriteLine();
- }
-
- private static void WriteFile (string filename, FileMode mode, Action<TextWriter> action)
- {
- Action<string> creator = file => {
- using (var writer = OpenWrite (file, mode))
- action (writer);
- };
-
- MdocFile.UpdateFile (filename, creator);
- }
-
- private static void OrderTypeAttributes (XmlElement e)
- {
- foreach (XmlElement type in e.SelectNodes ("//Type")) {
- OrderTypeAttributes (type.Attributes);
- }
- }
-
- static readonly string[] TypeAttributeOrder = {
- "Name", "FullName", "FullNameSP", "Maintainer"
- };
-
- private static void OrderTypeAttributes (XmlAttributeCollection c)
- {
- XmlAttribute[] attrs = new XmlAttribute [TypeAttributeOrder.Length];
- for (int i = 0; i < c.Count; ++i) {
- XmlAttribute a = c [i];
- for (int j = 0; j < TypeAttributeOrder.Length; ++j) {
- if (a.Name == TypeAttributeOrder [j]) {
- attrs [j] = a;
- break;
- }
- }
- }
- for (int i = attrs.Length-1; i >= 0; --i) {
- XmlAttribute n = attrs [i];
- if (n == null)
- continue;
- XmlAttribute r = null;
- for (int j = i+1; j < attrs.Length; ++j) {
- if (attrs [j] != null) {
- r = attrs [j];
- break;
- }
- }
- if (r == null)
- continue;
- if (c [n.Name] != null) {
- c.RemoveNamedItem (n.Name);
- c.InsertBefore (n, r);
- }
- }
- }
-
- private XmlDocument CreateIndexStub()
- {
- XmlDocument index = new XmlDocument();
-
- XmlElement index_root = index.CreateElement("Overview");
- index.AppendChild(index_root);
-
- if (assemblies.Count == 0)
- throw new Exception ("No assembly");
-
- XmlElement index_assemblies = index.CreateElement("Assemblies");
- index_root.AppendChild(index_assemblies);
-
- XmlElement index_remarks = index.CreateElement("Remarks");
- index_remarks.InnerText = "To be added.";
- index_root.AppendChild(index_remarks);
-
- XmlElement index_copyright = index.CreateElement("Copyright");
- index_copyright.InnerText = "To be added.";
- index_root.AppendChild(index_copyright);
-
- XmlElement index_types = index.CreateElement("Types");
- index_root.AppendChild(index_types);
-
- return index;
- }
-
- private static void WriteNamespaceStub(string ns, string outdir) {
- XmlDocument index = new XmlDocument();
-
- XmlElement index_root = index.CreateElement("Namespace");
- index.AppendChild(index_root);
-
- index_root.SetAttribute("Name", ns);
-
- XmlElement index_docs = index.CreateElement("Docs");
- index_root.AppendChild(index_docs);
-
- XmlElement index_summary = index.CreateElement("summary");
- index_summary.InnerText = "To be added.";
- index_docs.AppendChild(index_summary);
-
- XmlElement index_remarks = index.CreateElement("remarks");
- index_remarks.InnerText = "To be added.";
- index_docs.AppendChild(index_remarks);
-
- WriteFile (outdir + "/ns-" + ns + ".xml", FileMode.CreateNew,
- writer => WriteXml (index.DocumentElement, writer));
- }
-
- public void DoUpdateTypes (string basepath, List<string> typenames, string dest)
- {
- var index = CreateIndexForTypes (dest);
-
- var found = new HashSet<string> ();
- foreach (var assemblySet in this.assemblies) {
- using (assemblySet) {
- foreach (AssemblyDefinition assembly in assemblySet.Assemblies) {
- var frameworkEntry = frameworks.StartProcessingAssembly (assembly, assemblySet.Importers);
-
- foreach (TypeDefinition type in docEnum.GetDocumentationTypes (assembly, typenames)) {
- var typeEntry = frameworkEntry.ProcessType (type);
-
- string relpath = DoUpdateType (type, typeEntry, basepath, dest);
- if (relpath == null)
- continue;
-
- found.Add (type.FullName);
-
- if (index == null)
- continue;
-
- index.Add (assembly);
- index.Add (type);
- }
- }
- }
- }
-
- if (index != null)
- index.Write ();
-
- if (ignore_missing_types)
- return;
-
- var notFound = from n in typenames where !found.Contains (n) select n;
- if (notFound.Any ())
- throw new InvalidOperationException("Type(s) not found: " + string.Join (", ", notFound.ToArray ()));
- }
-
- class IndexForTypes {
-
- MDocUpdater app;
- string indexFile;
-
- XmlDocument index;
- XmlElement index_types;
- XmlElement index_assemblies;
-
- public IndexForTypes (MDocUpdater app, string indexFile, XmlDocument index)
- {
- this.app = app;
- this.indexFile = indexFile;
- this.index = index;
-
- index_types = WriteElement (index.DocumentElement, "Types");
- index_assemblies = WriteElement (index.DocumentElement, "Assemblies");
- }
-
- public void Add (AssemblyDefinition assembly)
- {
- if (index_assemblies.SelectSingleNode ("Assembly[@Name='" + assembly.Name.Name + "']") != null)
- return;
-
- app.AddIndexAssembly (assembly, index_assemblies);
- }
-
- public void Add (TypeDefinition type)
- {
- app.AddIndexType (type, index_types);
- }
-
- public void Write ()
- {
- SortIndexEntries (index_types);
- WriteFile (indexFile, FileMode.Create,
- writer => WriteXml (index.DocumentElement, writer));
- }
- }
-
- IndexForTypes CreateIndexForTypes (string dest)
- {
- string indexFile = Path.Combine (dest, "index.xml");
- if (File.Exists (indexFile))
- return null;
- return new IndexForTypes (this, indexFile, CreateIndexStub ());
- }
-
- /// <summary>Constructs the presumed path to the type's documentation file</summary>
- /// <returns><c>true</c>, if the type file was found, <c>false</c> otherwise.</returns>
- /// <param name="result">A typle that contains 1) the 'reltypefile', 2) the 'typefile', and 3) the file info</param>
- bool TryFindTypeFile(string nsname, string typename, string basepath, out Tuple<string, string, FileInfo> result) {
- string reltypefile = DocUtils.PathCombine (nsname, typename + ".xml");
- string typefile = Path.Combine (basepath, reltypefile);
- System.IO.FileInfo file = new System.IO.FileInfo(typefile);
-
- result = new Tuple<string, string, FileInfo> (reltypefile, typefile, file);
-
- return file.Exists;
- }
-
- public string DoUpdateType (TypeDefinition type, FrameworkTypeEntry typeEntry, string basepath, string dest)
- {
- if (type.Namespace == null)
- Warning ("warning: The type `{0}' is in the root namespace. This may cause problems with display within monodoc.",
- type.FullName);
- if (!IsPublic (type))
- return null;
-
- // Must get the A+B form of the type name.
- string typename = GetTypeFileName(type);
- string nsname = DocUtils.GetNamespace (type);
-
- // Find the file, if it exists
- string[] searchLocations = new string[] {
- nsname
- };
-
- if (MDocUpdater.HasDroppedNamespace (type)) {
- // If dropping namespace, types may have moved into a couple of different places.
- var newSearchLocations = searchLocations.Union (new string[] {
- string.Format ("{0}.{1}", droppedNamespace, nsname),
- nsname.Replace (droppedNamespace + ".", string.Empty),
- MDocUpdater.droppedNamespace
- });
-
- searchLocations = newSearchLocations.ToArray ();
- }
-
- string reltypefile="", typefile="";
- System.IO.FileInfo file = null;
-
- foreach (var f in searchLocations) {
- Tuple<string, string, FileInfo> result;
- bool fileExists = TryFindTypeFile (f, typename, basepath, out result);
-
- if (fileExists) {
- reltypefile = result.Item1;
- typefile = result.Item2;
- file = result.Item3;
-
- break;
- }
- }
-
- if (file == null || !file.Exists) {
- // we were not able to find a file, let's use the original type informatio.
- // so that we create the stub in the right place.
- Tuple<string, string, FileInfo> result;
- TryFindTypeFile (nsname, typename, basepath, out result);
-
- reltypefile = result.Item1;
- typefile = result.Item2;
- file = result.Item3;
- }
-
- string output = null;
- if (dest == null) {
- output = typefile;
- } else if (dest == "-") {
- output = null;
- } else {
- output = Path.Combine (dest, reltypefile);
- }
-
- if (file != null && file.Exists) {
- // Update
- XmlDocument basefile = new XmlDocument();
- try {
- basefile.Load(typefile);
- } catch (Exception e) {
- throw new InvalidOperationException("Error loading " + typefile + ": " + e.Message, e);
- }
-
- DoUpdateType2("Updating", basefile, type, typeEntry, output, false);
- } else {
- // Stub
- XmlElement td = StubType(type, output, typeEntry.Framework.Importers);
- if (td == null)
- return null;
- }
- return reltypefile;
- }
-
- private static string GetTypeFileName (TypeReference type)
- {
- return filenameFormatter.GetName (type);
- }
-
- public static string GetTypeFileName (string typename)
- {
- StringBuilder filename = new StringBuilder (typename.Length);
- int numArgs = 0;
- int numLt = 0;
- bool copy = true;
- for (int i = 0; i < typename.Length; ++i) {
- char c = typename [i];
- switch (c) {
- case '<':
- copy = false;
- ++numLt;
- break;
- case '>':
- --numLt;
- if (numLt == 0) {
- filename.Append ('`').Append ((numArgs+1).ToString());
- numArgs = 0;
- copy = true;
- }
- break;
- case ',':
- if (numLt == 1)
- ++numArgs;
- break;
- default:
- if (copy)
- filename.Append (c);
- break;
- }
- }
- return filename.ToString ();
- }
-
- private void AddIndexAssembly (AssemblyDefinition assembly, XmlElement parent)
- {
- XmlElement index_assembly = null;
- if (IsMultiAssembly)
- index_assembly = (XmlElement)parent.SelectSingleNode ("Assembly[@Name='"+ assembly.Name.Name +"']");
-
- if (index_assembly == null)
- index_assembly = parent.OwnerDocument.CreateElement ("Assembly");
-
- index_assembly.SetAttribute ("Name", assembly.Name.Name);
- index_assembly.SetAttribute ("Version", assembly.Name.Version.ToString());
-
- AssemblyNameDefinition name = assembly.Name;
- if (name.HasPublicKey) {
- XmlElement pubkey = parent.OwnerDocument.CreateElement ("AssemblyPublicKey");
- var key = new StringBuilder (name.PublicKey.Length*3 + 2);
- key.Append ("[");
- foreach (byte b in name.PublicKey)
- key.AppendFormat ("{0,2:x2} ", b);
- key.Append ("]");
- pubkey.InnerText = key.ToString ();
- index_assembly.AppendChild (pubkey);
- }
-
- if (!string.IsNullOrEmpty (name.Culture)) {
- XmlElement culture = parent.OwnerDocument.CreateElement ("AssemblyCulture");
- culture.InnerText = name.Culture;
- index_assembly.AppendChild (culture);
- }
-
- MakeAttributes (index_assembly, GetCustomAttributes (assembly.CustomAttributes, ""));
- parent.AppendChild(index_assembly);
- }
-
- private void AddIndexType (TypeDefinition type, XmlElement index_types)
- {
- string typename = GetTypeFileName(type);
-
- // Add namespace and type nodes into the index file as needed
- string ns = DocUtils.GetNamespace (type);
- XmlElement nsnode = (XmlElement) index_types.SelectSingleNode ("Namespace[@Name='" + ns + "']");
- if (nsnode == null) {
- nsnode = index_types.OwnerDocument.CreateElement("Namespace");
- nsnode.SetAttribute ("Name", ns);
- index_types.AppendChild (nsnode);
- }
- string doc_typename = GetDocTypeName (type);
- XmlElement typenode = (XmlElement) nsnode.SelectSingleNode ("Type[@Name='" + typename + "']");
- if (typenode == null) {
- typenode = index_types.OwnerDocument.CreateElement ("Type");
- typenode.SetAttribute ("Name", typename);
- nsnode.AppendChild (typenode);
- }
- if (typename != doc_typename)
- typenode.SetAttribute("DisplayName", doc_typename);
- else
- typenode.RemoveAttribute("DisplayName");
-
- typenode.SetAttribute ("Kind", GetTypeKind (type));
- }
-
- private void DoUpdateAssemblies (string source, string dest)
- {
- string indexfile = dest + "/index.xml";
- XmlDocument index;
- if (System.IO.File.Exists(indexfile)) {
- index = new XmlDocument();
- index.Load(indexfile);
-
- // Format change
- ClearElement(index.DocumentElement, "Assembly");
- ClearElement(index.DocumentElement, "Attributes");
- } else {
- index = CreateIndexStub();
- }
-
- XmlElement index_types = WriteElement(index.DocumentElement, "Types");
- XmlElement index_assemblies = WriteElement(index.DocumentElement, "Assemblies");
- if (!IsMultiAssembly)
- index_assemblies.RemoveAll ();
-
-
- HashSet<string> goodfiles = new HashSet<string> (StringComparer.OrdinalIgnoreCase);
-
- int processedAssemblyCount = 0;
- foreach (var assemblySet in assemblies) {
- using (assemblySet) {
- foreach (AssemblyDefinition assm in assemblySet.Assemblies) {
- AddIndexAssembly (assm, index_assemblies);
- DoUpdateAssembly (assemblySet, assm, index_types, source, dest, goodfiles);
- processedAssemblyCount++;
- }
- }
- }
-
- string defaultTitle = "Untitled";
- if (processedAssemblyCount == 1)
- defaultTitle = assemblies[0].Assemblies.First ().Name.Name;
- WriteElementInitialText (index.DocumentElement, "Title", defaultTitle);
-
- SortIndexEntries (index_types);
-
- CleanupFiles (dest, goodfiles);
- CleanupIndexTypes (index_types, goodfiles);
- CleanupExtensions (index_types);
-
- WriteFile (indexfile, FileMode.Create,
- writer => WriteXml(index.DocumentElement, writer));
- }
-
- private static char[] InvalidFilenameChars = {'\\', '/', ':', '*', '?', '"', '<', '>', '|'};
-
- private void DoUpdateAssembly (AssemblySet assemblySet, AssemblyDefinition assembly, XmlElement index_types, string source, string dest, HashSet<string> goodfiles)
- {
- var frameworkEntry = frameworks.StartProcessingAssembly (assembly, assemblySet.Importers);
-
- foreach (TypeDefinition type in docEnum.GetDocumentationTypes (assembly, null)) {
- string typename = GetTypeFileName(type);
- if (!IsPublic (type) || typename.IndexOfAny (InvalidFilenameChars) >= 0)
- continue;
-
- var typeEntry = frameworkEntry.ProcessType (type);
-
- string reltypepath = DoUpdateType (type, typeEntry, source, dest);
- if (reltypepath == null)
- continue;
-
- // Add namespace and type nodes into the index file as needed
- AddIndexType (type, index_types);
-
- // Ensure the namespace index file exists
- string namespaceToUse = type.Namespace;
- if (HasDroppedNamespace(assembly)) {
- namespaceToUse = string.Format ("{0}.{1}", droppedNamespace, namespaceToUse);
- }
- string onsdoc = DocUtils.PathCombine (dest, namespaceToUse + ".xml");
- string nsdoc = DocUtils.PathCombine (dest, "ns-" + namespaceToUse + ".xml");
- if (File.Exists (onsdoc)) {
- File.Move (onsdoc, nsdoc);
- }
-
- if (!File.Exists (nsdoc)) {
- Console.WriteLine("New Namespace File: " + type.Namespace);
- WriteNamespaceStub(namespaceToUse, dest);
- }
-
- goodfiles.Add (reltypepath);
- }
- }
-
- private static void SortIndexEntries (XmlElement indexTypes)
- {
- XmlNodeList namespaces = indexTypes.SelectNodes ("Namespace");
- XmlNodeComparer c = new AttributeNameComparer ();
- SortXmlNodes (indexTypes, namespaces, c);
-
- for (int i = 0; i < namespaces.Count; ++i)
- SortXmlNodes (namespaces [i], namespaces [i].SelectNodes ("Type"), c);
- }
-
- private static void SortXmlNodes (XmlNode parent, XmlNodeList children, XmlNodeComparer comparer)
- {
- MyXmlNodeList l = new MyXmlNodeList (children.Count);
- for (int i = 0; i < children.Count; ++i)
- l.Add (children [i]);
- l.Sort (comparer);
- for (int i = l.Count - 1; i > 0; --i) {
- parent.InsertBefore (parent.RemoveChild ((XmlNode) l [i-1]), (XmlNode) l [i]);
- }
- }
-
- abstract class XmlNodeComparer : IComparer, IComparer<XmlNode>
- {
- public abstract int Compare (XmlNode x, XmlNode y);
-
- public int Compare (object x, object y)
- {
- return Compare ((XmlNode) x, (XmlNode) y);
- }
- }
-
- class AttributeNameComparer : XmlNodeComparer {
- string attribute;
-
- public AttributeNameComparer ()
- : this ("Name")
- {
- }
-
- public AttributeNameComparer (string attribute)
- {
- this.attribute = attribute;
- }
-
- public override int Compare (XmlNode x, XmlNode y)
- {
- return x.Attributes [attribute].Value.CompareTo (y.Attributes [attribute].Value);
- }
- }
-
- class VersionComparer : XmlNodeComparer {
- public override int Compare (XmlNode x, XmlNode y)
- {
- // Some of the existing docs use e.g. 1.0.x.x, which Version doesn't like.
- string a = GetVersion (x.InnerText);
- string b = GetVersion (y.InnerText);
- return new Version (a).CompareTo (new Version (b));
- }
-
- static string GetVersion (string v)
- {
- int n = v.IndexOf ("x");
- if (n < 0)
- return v;
- return v.Substring (0, n-1);
- }
- }
-
- private static string GetTypeKind (TypeDefinition type)
- {
- if (type.IsEnum)
- return "Enumeration";
- if (type.IsValueType)
- return "Structure";
- if (type.IsInterface)
- return "Interface";
- if (DocUtils.IsDelegate (type))
- return "Delegate";
- if (type.IsClass || type.FullName == "System.Enum") // FIXME
- return "Class";
- throw new ArgumentException ("Unknown kind for type: " + type.FullName);
- }
-
- public static bool IsPublic (TypeDefinition type)
- {
- TypeDefinition decl = type;
- while (decl != null) {
- if (!(decl.IsPublic || decl.IsNestedPublic ||
- decl.IsNestedFamily || decl.IsNestedFamily || decl.IsNestedFamilyOrAssembly)) {
- return false;
- }
- decl = (TypeDefinition) decl.DeclaringType;
- }
- return true;
- }
-
- private void CleanupFiles (string dest, HashSet<string> goodfiles)
- {
- // Look for files that no longer correspond to types
- foreach (System.IO.DirectoryInfo nsdir in new System.IO.DirectoryInfo(dest).GetDirectories("*").Where(d => Path.GetFileName(d.FullName) != "FrameworksIndex")) {
- foreach (System.IO.FileInfo typefile in nsdir.GetFiles("*.xml")) {
- string relTypeFile = Path.Combine(nsdir.Name, typefile.Name);
- if (!goodfiles.Contains (relTypeFile)) {
- XmlDocument doc = new XmlDocument ();
- doc.Load (typefile.FullName);
- XmlElement e = doc.SelectSingleNode("/Type") as XmlElement;
- var assemblyNameNode = doc.SelectSingleNode ("/Type/AssemblyInfo/AssemblyName");
- if (assemblyNameNode == null){
- Warning ("Did not find /Type/AssemblyInfo/AssemblyName on {0}", typefile.FullName);
- continue;
- }
- string assemblyName = assemblyNameNode.InnerText;
-
-
- Action saveDoc = () => {
- using (TextWriter writer = OpenWrite (typefile.FullName, FileMode.Truncate))
- WriteXml(doc.DocumentElement, writer);
- };
-
- if (!IsMultiAssembly) { // only do this for "regular" runs
- AssemblyDefinition assembly = assemblies
- .SelectMany (aset => aset.Assemblies)
- .FirstOrDefault (a => a.Name.Name == assemblyName);
- if (e != null && !no_assembly_versions && assembly != null && assemblyName != null && UpdateAssemblyVersions (e, assembly, GetAssemblyVersions (assemblyName), false)) {
- saveDoc ();
- goodfiles.Add (relTypeFile);
- continue;
- }
- }
-
- Action actuallyDelete = () => {
- string newname = typefile.FullName + ".remove";
- try { System.IO.File.Delete (newname); } catch (Exception) { Warning ("Unable to delete existing file: {0}", newname); }
- try { typefile.MoveTo (newname); } catch (Exception) { Warning ("Unable to rename to: {0}", newname); }
- Console.WriteLine ("Class no longer present; file renamed: " + Path.Combine (nsdir.Name, typefile.Name));
- };
-
- if (string.IsNullOrWhiteSpace (PreserveTag)) { // only do this if there was not a -preserve
- saveDoc ();
-
- var unifiedAssemblyNode = doc.SelectSingleNode ("/Type/AssemblyInfo[@apistyle='unified']");
- var classicAssemblyNode = doc.SelectSingleNode ("/Type/AssemblyInfo[not(@apistyle) or @apistyle='classic']");
- var unifiedMembers = doc.SelectNodes ("//Member[@apistyle='unified']|//Member/AssemblyInfo[@apistyle='unified']");
- var classicMembers = doc.SelectNodes ("//Member[@apistyle='classic']|//Member/AssemblyInfo[@apistyle='classic']");
- bool isUnifiedRun = HasDroppedAnyNamespace ();
- bool isClassicOrNormalRun = !isUnifiedRun;
-
- Action<XmlNode, ApiStyle> removeStyles = (x, style) => {
- var styledNodes = doc.SelectNodes("//*[@apistyle='"+ style.ToString ().ToLowerInvariant () +"']");
- if (styledNodes != null && styledNodes.Count > 0) {
- foreach(var node in styledNodes.Cast<XmlNode> ()) {
- node.ParentNode.RemoveChild (node);
- }
- }
- saveDoc ();
- };
- if (isClassicOrNormalRun) {
- if (unifiedAssemblyNode != null || unifiedMembers.Count > 0) {
- Warning ("*** this type is marked as unified, not deleting during this run: {0}", typefile.FullName);
- // if truly removed from both assemblies, it will be removed fully during the unified run
- removeStyles (doc, ApiStyle.Classic);
- continue;
- } else {
- // we should be safe to delete here because it was not marked as a unified assembly
- actuallyDelete ();
- }
- }
- if (isUnifiedRun) {
- if (classicAssemblyNode != null || classicMembers.Count > 0) {
- Warning ("*** this type is marked as classic, not deleting {0}", typefile.FullName);
- continue;
- } else {
- // safe to delete because it wasn't marked as a classic assembly, so the type is gone in both.
- actuallyDelete ();
- }
- }
- }
- }
- }
- }
- }
-
- private static TextWriter OpenWrite (string path, FileMode mode)
- {
- var w = new StreamWriter (
- new FileStream (path, mode),
- new UTF8Encoding (false)
- );
- w.NewLine = "\n";
- return w;
- }
-
- private string[] GetAssemblyVersions (string assemblyName)
- {
- return (from a in assemblies.SelectMany(aset => aset.Assemblies)
- where a.Name.Name == assemblyName
- select GetAssemblyVersion (a)).ToArray ();
- }
-
- private static void CleanupIndexTypes (XmlElement index_types, HashSet<string> goodfiles)
- {
- // Look for type nodes that no longer correspond to types
- MyXmlNodeList remove = new MyXmlNodeList ();
- foreach (XmlElement typenode in index_types.SelectNodes("Namespace/Type")) {
- string fulltypename = Path.Combine (((XmlElement)typenode.ParentNode).GetAttribute("Name"), typenode.GetAttribute("Name") + ".xml");
- if (!goodfiles.Contains (fulltypename)) {
- remove.Add (typenode);
- }
- }
- foreach (XmlNode n in remove)
- n.ParentNode.RemoveChild (n);
- }
-
- private void CleanupExtensions (XmlElement index_types)
- {
- XmlNode e = index_types.SelectSingleNode ("/Overview/ExtensionMethods");
- if (extensionMethods.Count == 0) {
- if (e == null)
- return;
- index_types.SelectSingleNode ("/Overview").RemoveChild (e);
- return;
- }
- if (e == null) {
- e = index_types.OwnerDocument.CreateElement ("ExtensionMethods");
- index_types.SelectSingleNode ("/Overview").AppendChild (e);
- }
- else
- e.RemoveAll ();
- extensionMethods.Sort (DefaultExtensionMethodComparer);
- foreach (XmlNode m in extensionMethods) {
- e.AppendChild (index_types.OwnerDocument.ImportNode (m, true));
- }
- }
-
- class ExtensionMethodComparer : XmlNodeComparer {
- public override int Compare (XmlNode x, XmlNode y)
- {
- XmlNode xLink = x.SelectSingleNode ("Member/Link");
- XmlNode yLink = y.SelectSingleNode ("Member/Link");
-
- int n = xLink.Attributes ["Type"].Value.CompareTo (
- yLink.Attributes ["Type"].Value);
- if (n != 0)
- return n;
- n = xLink.Attributes ["Member"].Value.CompareTo (
- yLink.Attributes ["Member"].Value);
- if (n == 0 && !object.ReferenceEquals (x, y))
- throw new InvalidOperationException ("Duplicate extension method found!");
- return n;
- }
- }
-
- static readonly XmlNodeComparer DefaultExtensionMethodComparer = new ExtensionMethodComparer ();
-
- public void DoUpdateType2 (string message, XmlDocument basefile, TypeDefinition type, FrameworkTypeEntry typeEntry, string output, bool insertSince)
- {
- Console.WriteLine(message + ": " + type.FullName);
-
- StringToXmlNodeMap seenmembers = new StringToXmlNodeMap ();
-
- // Update type metadata
- UpdateType(basefile.DocumentElement, type, typeEntry);
-
- // Update existing members. Delete member nodes that no longer should be there,
- // and remember what members are already documented so we don't add them again.
-
- MyXmlNodeList todelete = new MyXmlNodeList ();
-
- foreach (DocsNodeInfo info in docEnum.GetDocumentationMembers (basefile, type)) {
- XmlElement oldmember = info.Node;
- MemberReference oldmember2 = info.Member;
-
- if (info.Member != null && info.Node != null) {
- // Check for an error condition where the xml MemberName doesn't match the matched member
- var memberName = GetMemberName (info.Member);
- var memberAttribute = info.Node.Attributes ["MemberName"];
- if (memberAttribute == null || (memberAttribute.Value != memberName && memberAttribute.Value.Split (',').Length != memberName.Split (',').Length)) {
- oldmember.SetAttribute ("MemberName", memberName);
- }
- }
-
- string sig = oldmember2 != null ? memberFormatters [1].GetDeclaration (oldmember2) : null;
-
- // Interface implementations and overrides are deleted from the docs
- // unless the overrides option is given.
- if (oldmember2 != null && sig == null)
- oldmember2 = null;
-
- // Deleted (or signature changed)
- if (oldmember2 == null) {
- if (!string.IsNullOrWhiteSpace (FrameworksPath)) {
- // verify that this member wasn't seen in another framework and is indeed valid
- var sigFromXml = oldmember
- .GetElementsByTagName ("MemberSignature")
- .Cast<XmlElement> ()
- .FirstOrDefault (x => x.GetAttribute ("Language").Equals ("ILAsm"));
-
- if (sigFromXml != null) {
- var sigvalue = sigFromXml.GetAttribute ("Value");
- Func<FrameworkEntry, bool> findTypes = fx => {
- var tInstance = fx.Types.FirstOrDefault(t => t.Equals(typeEntry));
- if (tInstance != null) {
- return tInstance.ContainsCSharpSig(sigvalue);
- }
- return false;
- };
- if (frameworksCache.Frameworks.Any (findTypes))
- continue;
- }
- }
-
- if (!no_assembly_versions && UpdateAssemblyVersions (oldmember, type.Module.Assembly, new string[]{ GetAssemblyVersion (type.Module.Assembly) }, false))
- continue;
-
- DeleteMember ("Member Removed", output, oldmember, todelete, type);
- continue;
- }
-
- // Duplicated
- if (seenmembers.ContainsKey (sig)) {
- if (object.ReferenceEquals (oldmember, seenmembers [sig])) {
- // ignore, already seen
- }
- else
- DeleteMember ("Duplicate Member Found", output, oldmember, todelete, type);
-
- continue;
- }
-
- // Update signature information
- UpdateMember(info, typeEntry);
-
- // get all apistyles of sig from info.Node
- var styles = oldmember.GetElementsByTagName ("MemberSignature").Cast<XmlElement> ()
- .Where (x => x.GetAttribute ("Language") == "ILAsm" && !seenmembers.ContainsKey(x.GetAttribute("Value")))
- .Select (x => x.GetAttribute ("Value"));
-
-
- typeEntry.ProcessMember (info.Member);
-
- foreach (var stylesig in styles) {
- seenmembers.Add (stylesig, oldmember);
- }
- }
- foreach (XmlElement oldmember in todelete)
- oldmember.ParentNode.RemoveChild (oldmember);
-
-
- if (!DocUtils.IsDelegate (type)) {
- XmlNode members = WriteElement (basefile.DocumentElement, "Members");
- var typemembers = type.GetMembers()
- .Where(m => {
- if (m is TypeDefinition) return false;
- string cssig = memberFormatters [0].GetDeclaration (m);
- if (cssig == null) return false;
- string sig = memberFormatters [1].GetDeclaration (m);
- if (seenmembers.ContainsKey(sig)) return false;
-
- // Verify that the member isn't an explicitly implemented
- // member of an internal interface, in which case we shouldn't return true.
- MethodDefinition methdef = null;
- if (m is MethodDefinition)
- methdef = m as MethodDefinition;
- else if (m is PropertyDefinition) {
- var prop = m as PropertyDefinition;
- methdef = prop.GetMethod ?? prop.SetMethod;
- }
-
- if (methdef != null) {
- TypeReference iface;
- MethodReference imethod;
-
- if (methdef.Overrides.Count == 1 && !methdef.IsPublic) {
- DocUtils.GetInfoForExplicitlyImplementedMethod (methdef, out iface, out imethod);
- if (!IsPublic (iface.Resolve ())) return false;
- }
- }
-
- return true;
- })
- .ToArray();
- foreach (MemberReference m in typemembers) {
- XmlElement mm = MakeMember(basefile, new DocsNodeInfo (null, m), members, typeEntry);
- if (mm == null) continue;
-
- if (MDocUpdater.SwitchingToMagicTypes || MDocUpdater.HasDroppedNamespace (m)) {
- // this is a unified style API that obviously doesn't exist in the classic API. Let's mark
- // it with apistyle="unified", so that it's not displayed for classic style APIs
- mm.AddApiStyle (ApiStyle.Unified);
- }
-
- Console.WriteLine("Member Added: " + mm.SelectSingleNode("MemberSignature/@Value").InnerText);
- additions++;
- }
- }
-
- // Import code snippets from files
- foreach (XmlNode code in basefile.GetElementsByTagName("code")) {
- if (!(code is XmlElement)) continue;
- string file = ((XmlElement)code).GetAttribute("src");
- string lang = ((XmlElement)code).GetAttribute("lang");
- if (file != "") {
- string src = GetCodeSource (lang, Path.Combine (srcPath, file));
- if (src != null)
- code.InnerText = src;
- }
- }
-
- if (insertSince && since != null) {
- XmlNode docs = basefile.DocumentElement.SelectSingleNode("Docs");
- docs.AppendChild (CreateSinceNode (basefile));
- }
-
- do {
- XmlElement d = basefile.DocumentElement ["Docs"];
- XmlElement m = basefile.DocumentElement ["Members"];
- if (d != null && m != null)
- basefile.DocumentElement.InsertBefore (
- basefile.DocumentElement.RemoveChild (d), m);
- SortTypeMembers (m);
- } while (false);
-
- if (output == null)
- WriteXml(basefile.DocumentElement, Console.Out);
- else {
- FileInfo file = new FileInfo (output);
- if (!file.Directory.Exists) {
- Console.WriteLine("Namespace Directory Created: " + type.Namespace);
- file.Directory.Create ();
- }
- WriteFile (output, FileMode.Create,
- writer => WriteXml(basefile.DocumentElement, writer));
- }
- }
-
- private string GetCodeSource (string lang, string file)
- {
- int anchorStart;
- if (lang == "C#" && (anchorStart = file.IndexOf (".cs#")) >= 0) {
- // Grab the specified region
- string region = "#region " + file.Substring (anchorStart + 4);
- file = file.Substring (0, anchorStart + 3);
- try {
- using (StreamReader reader = new StreamReader (file)) {
- string line;
- StringBuilder src = new StringBuilder ();
- int indent = -1;
- while ((line = reader.ReadLine ()) != null) {
- if (line.Trim() == region) {
- indent = line.IndexOf (region);
- continue;
- }
- if (indent >= 0 && line.Trim().StartsWith ("#endregion")) {
- break;
- }
- if (indent >= 0)
- src.Append (
- (line.Length > 0 ? line.Substring (indent) : string.Empty) +
- "\n");
- }
- return src.ToString ();
- }
- } catch (Exception e) {
- Warning ("Could not load <code/> file '{0}' region '{1}': {2}",
- file, region, show_exceptions ? e.ToString () : e.Message);
- return null;
- }
- }
- try {
- using (StreamReader reader = new StreamReader (file))
- return reader.ReadToEnd ();
- } catch (Exception e) {
- Warning ("Could not load <code/> file '" + file + "': " + e.Message);
- }
- return null;
- }
-
- void DeleteMember (string reason, string output, XmlNode member, MyXmlNodeList todelete, TypeDefinition type)
- {
- string format = output != null
- ? "{0}: File='{1}'; Signature='{4}'"
- : "{0}: XPath='/Type[@FullName=\"{2}\"]/Members/Member[@MemberName=\"{3}\"]'; Signature='{4}'";
- string signature = member.SelectSingleNode ("MemberSignature[@Language='C#']/@Value").Value;
- Warning (format,
- reason,
- output,
- member.OwnerDocument.DocumentElement.GetAttribute ("FullName"),
- member.Attributes ["MemberName"].Value,
- signature);
-
- // Identify all of the different states that could affect our decision to delete the member
- bool shouldPreserve = !string.IsNullOrWhiteSpace (PreserveTag);
- bool hasContent = MemberDocsHaveUserContent (member);
- bool shouldDelete = !shouldPreserve && (delete || !hasContent);
-
- bool unifiedRun = HasDroppedNamespace (type);
-
- var classicAssemblyInfo = member.SelectSingleNode ("AssemblyInfo[not(@apistyle) or @apistyle='classic']");
- bool nodeIsClassic = classicAssemblyInfo != null || member.HasApiStyle (ApiStyle.Classic);
- var unifiedAssemblyInfo = member.SelectSingleNode ("AssemblyInfo[@apistyle='unified']");
- bool nodeIsUnified = unifiedAssemblyInfo != null || member.HasApiStyle (ApiStyle.Unified);
-
- Action actuallyDelete = () => {
- todelete.Add (member);
- deletions++;
- };
-
- if (!shouldDelete) {
- // explicitly not deleting
- string message = shouldPreserve ?
- "Not deleting '{0}' due to --preserve." :
- "Not deleting '{0}'; must be enabled with the --delete option";
- Warning (message, signature);
- } else if (unifiedRun && nodeIsClassic) {
- // this is a unified run, and the member doesn't exist, but is marked as being in the classic assembly.
- member.RemoveApiStyle (ApiStyle.Unified);
- member.AddApiStyle (ApiStyle.Classic);
- Warning ("Not removing '{0}' since it's still in the classic assembly.", signature);
- } else if (unifiedRun && !nodeIsClassic) {
- // unified run, and the node is not classic, which means it doesn't exist anywhere.
- actuallyDelete ();
- } else {
- if (!isClassicRun || (isClassicRun && !nodeIsClassic && !nodeIsUnified)) { // regular codepath (ie. not classic/unified)
- actuallyDelete ();
- } else { // this is a classic run
- Warning ("Removing classic from '{0}' ... will be removed in the unified run if not present there.", signature);
- member.RemoveApiStyle (ApiStyle.Classic);
- if (classicAssemblyInfo != null) {
- member.RemoveChild (classicAssemblyInfo);
- }
- }
- }
- }
-
- class MemberComparer : XmlNodeComparer {
- public override int Compare (XmlNode x, XmlNode y)
- {
- int r;
- string xMemberName = x.Attributes ["MemberName"].Value;
- string yMemberName = y.Attributes ["MemberName"].Value;
-
- // generic methods *end* with '>'
- // it's possible for explicitly implemented generic interfaces to
- // contain <...> without being a generic method
- if ((!xMemberName.EndsWith (">") || !yMemberName.EndsWith (">")) &&
- (r = xMemberName.CompareTo (yMemberName)) != 0)
- return r;
-
- int lt;
- if ((lt = xMemberName.IndexOf ("<")) >= 0)
- xMemberName = xMemberName.Substring (0, lt);
- if ((lt = yMemberName.IndexOf ("<")) >= 0)
- yMemberName = yMemberName.Substring (0, lt);
- if ((r = xMemberName.CompareTo (yMemberName)) != 0)
- return r;
-
- // Handle MemberGroup sorting
- var sc = StringComparison.InvariantCultureIgnoreCase;
- if (x.Name.Equals ("MemberGroup", sc) || y.Name.Equals ("MemberGroup", sc)) {
- if (x.Name.Equals ("MemberGroup", sc) && y.Name.Equals ("Member", sc))
- return -1;
- else if (x.Name.Equals ("Member", sc) && y.Name.Equals ("MemberGroup", sc))
- return 1;
- else
- return xMemberName.CompareTo (yMemberName);
- }
-
- // if @MemberName matches, then it's either two different types of
- // members sharing the same name, e.g. field & property, or it's an
- // overloaded method.
- // for different type, sort based on MemberType value.
- r = x.SelectSingleNode ("MemberType").InnerText.CompareTo (
- y.SelectSingleNode ("MemberType").InnerText);
- if (r != 0)
- return r;
-
- // same type -- must be an overloaded method. Sort based on type
- // parameter count, then parameter count, then by the parameter
- // type names.
- XmlNodeList xTypeParams = x.SelectNodes ("TypeParameters/TypeParameter");
- XmlNodeList yTypeParams = y.SelectNodes ("TypeParameters/TypeParameter");
- if (xTypeParams.Count != yTypeParams.Count)
- return xTypeParams.Count <= yTypeParams.Count ? -1 : 1;
- for (int i = 0; i < xTypeParams.Count; ++i) {
- r = xTypeParams [i].Attributes ["Name"].Value.CompareTo (
- yTypeParams [i].Attributes ["Name"].Value);
- if (r != 0)
- return r;
- }
-
- XmlNodeList xParams = x.SelectNodes ("Parameters/Parameter");
- XmlNodeList yParams = y.SelectNodes ("Parameters/Parameter");
- if (xParams.Count != yParams.Count)
- return xParams.Count <= yParams.Count ? -1 : 1;
- for (int i = 0; i < xParams.Count; ++i) {
- r = xParams [i].Attributes ["Type"].Value.CompareTo (
- yParams [i].Attributes ["Type"].Value);
- if (r != 0)
- return r;
- }
- // all parameters match, but return value might not match if it was
- // changed between one version and another.
- XmlNode xReturn = x.SelectSingleNode ("ReturnValue/ReturnType");
- XmlNode yReturn = y.SelectSingleNode ("ReturnValue/ReturnType");
- if (xReturn != null && yReturn != null) {
- r = xReturn.InnerText.CompareTo (yReturn.InnerText);
- if (r != 0)
- return r;
- }
-
- return 0;
- }
- }
-
- static readonly MemberComparer DefaultMemberComparer = new MemberComparer ();
-
- private static void SortTypeMembers (XmlNode members)
- {
- if (members == null)
- return;
- SortXmlNodes (members, members.SelectNodes ("Member|MemberGroup"), DefaultMemberComparer);
- }
-
- private static bool MemberDocsHaveUserContent (XmlNode e)
- {
- e = (XmlElement)e.SelectSingleNode("Docs");
- if (e == null) return false;
- foreach (XmlElement d in e.SelectNodes("*"))
- if (d.InnerText != "" && !d.InnerText.StartsWith("To be added"))
- return true;
- return false;
- }
-
- // UPDATE HELPER FUNCTIONS
-
- // CREATE A STUB DOCUMENTATION FILE
-
- public XmlElement StubType (TypeDefinition type, string output, IEnumerable<DocumentationImporter> importers)
- {
- string typesig = typeFormatters [0].GetDeclaration (type);
- if (typesig == null) return null; // not publicly visible
-
- XmlDocument doc = new XmlDocument();
- XmlElement root = doc.CreateElement("Type");
- doc.AppendChild (root);
-
- var frameworkEntry = frameworks.StartProcessingAssembly (type.Module.Assembly, importers);
- var typeEntry = frameworkEntry.ProcessType (type);
- DoUpdateType2 ("New Type", doc, type, typeEntry, output, true);
-
- return root;
- }
-
- private XmlElement CreateSinceNode (XmlDocument doc)
- {
- XmlElement s = doc.CreateElement ("since");
- s.SetAttribute ("version", since);
- return s;
- }
-
- // STUBBING/UPDATING FUNCTIONS
-
- public void UpdateType (XmlElement root, TypeDefinition type, FrameworkTypeEntry typeEntry)
- {
- root.SetAttribute("Name", GetDocTypeName (type));
- root.SetAttribute("FullName", GetDocTypeFullName (type));
-
- foreach (MemberFormatter f in typeFormatters) {
- string element = "TypeSignature[@Language='" + f.Language + "']";
- string valueToUse = f.GetDeclaration (type);
-
- AddXmlNode (
- root.SelectNodes (element).Cast<XmlElement> ().ToArray (),
- x => x.GetAttribute ("Value") == valueToUse,
- x => x.SetAttribute ("Value", valueToUse),
- () => {
- var node = WriteElementAttribute (root, element, "Language", f.Language, forceNewElement: true);
- var newnode = WriteElementAttribute (root, node, "Value", valueToUse);
- return newnode;
- },
- type);
- }
-
- AddAssemblyNameToNode (root, type);
-
- string assemblyInfoNodeFilter = MDocUpdater.HasDroppedNamespace (type) ? "[@apistyle='unified']" : "[not(@apistyle) or @apistyle='classic']";
- Func<XmlElement, bool> assemblyFilter = x => x.SelectSingleNode ("AssemblyName").InnerText == type.Module.Assembly.Name.Name;
- foreach(var ass in root.SelectNodes ("AssemblyInfo" + assemblyInfoNodeFilter).Cast<XmlElement> ().Where (assemblyFilter))
- {
- WriteElementText(ass, "AssemblyName", type.Module.Assembly.Name.Name);
- if (!no_assembly_versions) {
- UpdateAssemblyVersions (ass, type, true);
- }
- else {
- var versions = ass.SelectNodes ("AssemblyVersion").Cast<XmlNode> ().ToList ();
- foreach (var version in versions)
- ass.RemoveChild (version);
- }
- if (!string.IsNullOrEmpty (type.Module.Assembly.Name.Culture))
- WriteElementText(ass, "AssemblyCulture", type.Module.Assembly.Name.Culture);
- else
- ClearElement(ass, "AssemblyCulture");
-
-
- // Why-oh-why do we put assembly attributes in each type file?
- // Neither monodoc nor monodocs2html use them, so I'm deleting them
- // since they're outdated in current docs, and a waste of space.
- //MakeAttributes(ass, type.Assembly, true);
- XmlNode assattrs = ass.SelectSingleNode("Attributes");
- if (assattrs != null)
- ass.RemoveChild(assattrs);
-
- NormalizeWhitespace(ass);
- }
-
- if (type.IsGenericType ()) {
- MakeTypeParameters (root, type.GenericParameters, type, MDocUpdater.HasDroppedNamespace(type));
- } else {
- ClearElement(root, "TypeParameters");
- }
-
- if (type.BaseType != null) {
- XmlElement basenode = WriteElement(root, "Base");
-
- string basetypename = GetDocTypeFullName (type.BaseType);
- if (basetypename == "System.MulticastDelegate") basetypename = "System.Delegate";
-
- if (string.IsNullOrWhiteSpace (FrameworksPath))
- WriteElementText (root, "Base/BaseTypeName", basetypename);
- else {
- // Check for the possibility of an alternate inheritance chain in different frameworks
- var typeElements = basenode.GetElementsByTagName ("BaseTypeName");
-
- if (typeElements.Count == 0) // no existing elements, just add
- WriteElementText (root, "Base/BaseTypeName", basetypename);
- else {
- // There's already a BaseTypeName, see if it matches
- if (typeElements[0].InnerText != basetypename) {
- // Add a framework alternate if one doesn't already exist
- var existing = typeElements.Cast<XmlNode> ().Where (n => n.InnerText == basetypename);
- if (!existing.Any ()) {
- var newNode = WriteElementText (basenode, "BaseTypeName", basetypename, forceNewElement:true);
- WriteElementAttribute (basenode, newNode, "FrameworkAlternate", typeEntry.Framework.Name);
- }
- }
- }
- }
-
- // Document how this type instantiates the generic parameters of its base type
- TypeReference origBase = type.BaseType.GetElementType ();
- if (origBase.IsGenericType ()) {
- ClearElement(basenode, "BaseTypeArguments");
- GenericInstanceType baseInst = type.BaseType as GenericInstanceType;
- IList<TypeReference> baseGenArgs = baseInst == null ? null : baseInst.GenericArguments;
- IList<GenericParameter> baseGenParams = origBase.GenericParameters;
- if (baseGenArgs.Count != baseGenParams.Count)
- throw new InvalidOperationException ("internal error: number of generic arguments doesn't match number of generic parameters.");
- for (int i = 0; baseGenArgs != null && i < baseGenArgs.Count; i++) {
- GenericParameter param = baseGenParams [i];
- TypeReference value = baseGenArgs [i];
-
- XmlElement bta = WriteElement(basenode, "BaseTypeArguments");
- XmlElement arg = bta.OwnerDocument.CreateElement("BaseTypeArgument");
- bta.AppendChild(arg);
- arg.SetAttribute ("TypeParamName", param.Name);
- arg.InnerText = GetDocTypeFullName (value);
- }
- }
- } else {
- ClearElement(root, "Base");
- }
-
- if (!DocUtils.IsDelegate (type) && !type.IsEnum) {
- IEnumerable<TypeReference> userInterfaces = DocUtils.GetUserImplementedInterfaces (type);
- List<string> interface_names = userInterfaces
- .Select (iface => GetDocTypeFullName (iface))
- .OrderBy (s => s)
- .ToList ();
-
- XmlElement interfaces = WriteElement(root, "Interfaces");
- interfaces.RemoveAll();
- foreach (string iname in interface_names) {
- XmlElement iface = root.OwnerDocument.CreateElement("Interface");
- interfaces.AppendChild(iface);
- WriteElementText(iface, "InterfaceName", iname);
- }
- } else {
- ClearElement(root, "Interfaces");
- }
-
- MakeAttributes (root, GetCustomAttributes (type), type);
-
- if (DocUtils.IsDelegate (type)) {
- MakeTypeParameters (root, type.GenericParameters, type, MDocUpdater.HasDroppedNamespace(type));
- var member = type.GetMethod ("Invoke");
- MakeParameters(root, member, member.Parameters);
- MakeReturnValue(root, member);
- }
-
- DocsNodeInfo typeInfo = new DocsNodeInfo (WriteElement(root, "Docs"), type);
- MakeDocNode (typeInfo, typeEntry.Framework.Importers);
-
- if (!DocUtils.IsDelegate (type))
- WriteElement (root, "Members");
-
- OrderTypeNodes (root, root.ChildNodes);
- NormalizeWhitespace(root);
- }
-
- /// <summary>Adds an AssemblyInfo with AssemblyName node to an XmlElement.</summary>
- /// <returns>The assembly that was either added, or was already present</returns>
- XmlElement AddAssemblyNameToNode (XmlElement root, TypeDefinition type)
- {
- return AddAssemblyNameToNode (root, type.Module);
- }
-
- /// <summary>Adds an AssemblyInfo with AssemblyName node to an XmlElement.</summary>
- /// <returns>The assembly that was either added, or was already present</returns>
- XmlElement AddAssemblyNameToNode (XmlElement root, ModuleDefinition module)
- {
- Func<XmlElement, bool> assemblyFilter = x => {
- var existingName = x.SelectSingleNode ("AssemblyName");
-
- bool apiStyleMatches = true;
- string currentApiStyle = x.GetAttribute ("apistyle");
- if ((HasDroppedNamespace (module) && !string.IsNullOrWhiteSpace (currentApiStyle) && currentApiStyle != "unified") ||
- (isClassicRun && (string.IsNullOrWhiteSpace (currentApiStyle) || currentApiStyle != "classic"))) {
- apiStyleMatches = false;
- }
- return apiStyleMatches && (existingName == null || (existingName != null && existingName.InnerText == module.Assembly.Name.Name));
- };
-
- return AddAssemblyXmlNode (
- root.SelectNodes ("AssemblyInfo").Cast<XmlElement> ().ToArray (),
- assemblyFilter, x => WriteElementText (x, "AssemblyName", module.Assembly.Name.Name),
- () => {
- XmlElement ass = WriteElement (root, "AssemblyInfo", forceNewElement: true);
-
- if (MDocUpdater.HasDroppedNamespace (module))
- ass.AddApiStyle (ApiStyle.Unified);
- if (isClassicRun)
- ass.AddApiStyle (ApiStyle.Classic);
- return ass;
- }, module);
- }
-
- static readonly string[] TypeNodeOrder = {
- "TypeSignature",
- "MemberOfLibrary",
- "AssemblyInfo",
- "ThreadingSafetyStatement",
- "ThreadSafetyStatement",
- "TypeParameters",
- "Base",
- "Interfaces",
- "Attributes",
- "Parameters",
- "ReturnValue",
- "Docs",
- "Members",
- "TypeExcluded",
- };
-
- static void OrderTypeNodes (XmlNode member, XmlNodeList children)
- {
- ReorderNodes (member, children, TypeNodeOrder);
- }
-
- internal static IEnumerable<T> Sort<T> (IEnumerable<T> list)
- {
- List<T> l = new List<T> (list);
- l.Sort ();
- return l;
- }
-
- private void UpdateMember (DocsNodeInfo info, FrameworkTypeEntry typeEntry)
- {
- XmlElement me = (XmlElement) info.Node;
- MemberReference mi = info.Member;
- typeEntry.ProcessMember (mi);
- foreach (MemberFormatter f in memberFormatters) {
- string element = "MemberSignature[@Language='" + f.Language + "']";
-
- var valueToUse = f.GetDeclaration (mi);
-
- AddXmlNode (
- me.SelectNodes (element).Cast<XmlElement> ().ToArray(),
- x => x.GetAttribute("Value") == valueToUse,
- x => x.SetAttribute ("Value", valueToUse),
- () => {
- var node = WriteElementAttribute (me, element, "Language", f.Language, forceNewElement:true);
- var newNode = WriteElementAttribute (me, node, "Value", valueToUse);
- return newNode;
- },
- mi);
- }
-
- WriteElementText(me, "MemberType", GetMemberType(mi));
-
- if (!no_assembly_versions) {
- if (!IsMultiAssembly)
- UpdateAssemblyVersions (me, mi, true);
- else {
- var node = AddAssemblyNameToNode (me, mi.Module);
-
- UpdateAssemblyVersionForAssemblyInfo (node, me, new[] { GetAssemblyVersion (mi.Module.Assembly) }, add: true);
- }
- }
- else {
- ClearElement (me, "AssemblyInfo");
- }
-
- MakeAttributes (me, GetCustomAttributes (mi), mi.DeclaringType);
-
- MakeReturnValue(me, mi, MDocUpdater.HasDroppedNamespace(mi));
- if (mi is MethodReference) {
- MethodReference mb = (MethodReference) mi;
- if (mb.IsGenericMethod ())
- MakeTypeParameters (me, mb.GenericParameters, mi, MDocUpdater.HasDroppedNamespace(mi));
- }
- MakeParameters(me, mi, MDocUpdater.HasDroppedNamespace(mi));
-
- string fieldValue;
- if (mi is FieldDefinition && GetFieldConstValue ((FieldDefinition)mi, out fieldValue))
- WriteElementText(me, "MemberValue", fieldValue);
-
- info.Node = WriteElement (me, "Docs");
- MakeDocNode (info, typeEntry.Framework.Importers);
- OrderMemberNodes (me, me.ChildNodes);
- UpdateExtensionMethods (me, info);
- }
-
- static void AddXmlNode (XmlElement[] relevant, Func<XmlElement, bool> valueMatches, Action<XmlElement> setValue, Func<XmlElement> makeNewNode, MemberReference member) {
- AddXmlNode (relevant, valueMatches, setValue, makeNewNode, member.Module);
- }
-
- static void AddXmlNode (XmlElement[] relevant, Func<XmlElement, bool> valueMatches, Action<XmlElement> setValue, Func<XmlElement> makeNewNode, TypeDefinition type) {
- AddXmlNode (relevant, valueMatches, setValue, makeNewNode, type.Module);
- }
-
- static XmlElement AddAssemblyXmlNode (XmlElement[] relevant, Func<XmlElement, bool> valueMatches, Action<XmlElement> setValue, Func<XmlElement> makeNewNode, ModuleDefinition module)
- {
- bool isUnified = MDocUpdater.HasDroppedNamespace (module);
- XmlElement thisAssemblyNode = relevant.FirstOrDefault (valueMatches);
- if (thisAssemblyNode == null) {
- thisAssemblyNode = makeNewNode ();
- }
- setValue (thisAssemblyNode);
-
- if (isUnified) {
- thisAssemblyNode.AddApiStyle (ApiStyle.Unified);
-
- foreach (var otherNodes in relevant.Where (n => n != thisAssemblyNode && n.DoesNotHaveApiStyle (ApiStyle.Unified))) {
- otherNodes.AddApiStyle (ApiStyle.Classic);
- }
- }
- return thisAssemblyNode;
- }
-
- /// <summary>Adds an xml node, reusing the node if it's available</summary>
- /// <param name="relevant">The existing set of nodes</param>
- /// <param name="valueMatches">Checks to see if the node's value matches what you're trying to write.</param>
- /// <param name="setValue">Sets the node's value</param>
- /// <param name="makeNewNode">Creates a new node, if valueMatches returns false.</param>
- static void AddXmlNode (XmlElement[] relevant, Func<XmlElement, bool> valueMatches, Action<XmlElement> setValue, Func<XmlElement> makeNewNode, ModuleDefinition module)
- {
- bool shouldDuplicate = MDocUpdater.HasDroppedNamespace (module);
- var styleToUse = shouldDuplicate ? ApiStyle.Unified : ApiStyle.Classic;
- var existing = relevant;
- bool done = false;
- bool addedOldApiStyle = false;
-
- if (shouldDuplicate) {
- existing = existing.Where (n => n.HasApiStyle (styleToUse)).ToArray ();
- foreach (var n in relevant.Where (n => n.DoesNotHaveApiStyle (styleToUse))) {
- if (valueMatches (n)) {
- done = true;
- }
- else {
- n.AddApiStyle (ApiStyle.Classic);
- addedOldApiStyle = true;
- }
- }
- }
- if (!done) {
- if (!existing.Any ()) {
- var newNode = makeNewNode ();
- if (shouldDuplicate && addedOldApiStyle) {
- newNode.AddApiStyle (ApiStyle.Unified);
- }
- }
- else {
- var itemToReuse = existing.First ();
- setValue (itemToReuse);
-
- if (shouldDuplicate && addedOldApiStyle) {
- itemToReuse.AddApiStyle (styleToUse);
- }
- }
- }
- }
-
- static readonly string[] MemberNodeOrder = {
- "MemberSignature",
- "MemberType",
- "AssemblyInfo",
- "Attributes",
- "ReturnValue",
- "TypeParameters",
- "Parameters",
- "MemberValue",
- "Docs",
- "Excluded",
- "ExcludedLibrary",
- "Link",
- };
-
- static void OrderMemberNodes (XmlNode member, XmlNodeList children)
- {
- ReorderNodes (member, children, MemberNodeOrder);
- }
-
- static void ReorderNodes (XmlNode node, XmlNodeList children, string[] ordering)
- {
- MyXmlNodeList newChildren = new MyXmlNodeList (children.Count);
- for (int i = 0; i < ordering.Length; ++i) {
- for (int j = 0; j < children.Count; ++j) {
- XmlNode c = children [j];
- if (c.Name == ordering [i]) {
- newChildren.Add (c);
- }
- }
- }
- if (newChildren.Count >= 0)
- node.PrependChild ((XmlNode) newChildren [0]);
- for (int i = 1; i < newChildren.Count; ++i) {
- XmlNode prev = (XmlNode) newChildren [i-1];
- XmlNode cur = (XmlNode) newChildren [i];
- node.RemoveChild (cur);
- node.InsertAfter (cur, prev);
- }
- }
-
- IEnumerable<string> GetCustomAttributes (MemberReference mi)
- {
- IEnumerable<string> attrs = Enumerable.Empty<string>();
-
- ICustomAttributeProvider p = mi as ICustomAttributeProvider;
- if (p != null)
- attrs = attrs.Concat (GetCustomAttributes (p.CustomAttributes, ""));
-
- PropertyDefinition pd = mi as PropertyDefinition;
- if (pd != null) {
- if (pd.GetMethod != null)
- attrs = attrs.Concat (GetCustomAttributes (pd.GetMethod.CustomAttributes, "get: "));
- if (pd.SetMethod != null)
- attrs = attrs.Concat (GetCustomAttributes (pd.SetMethod.CustomAttributes, "set: "));
- }
-
- EventDefinition ed = mi as EventDefinition;
- if (ed != null) {
- if (ed.AddMethod != null)
- attrs = attrs.Concat (GetCustomAttributes (ed.AddMethod.CustomAttributes, "add: "));
- if (ed.RemoveMethod != null)
- attrs = attrs.Concat (GetCustomAttributes (ed.RemoveMethod.CustomAttributes, "remove: "));
- }
-
- return attrs;
- }
-
- IEnumerable<string> GetCustomAttributes (IList<CustomAttribute> attributes, string prefix)
- {
- foreach (CustomAttribute attribute in attributes.OrderBy (ca => ca.AttributeType.FullName)) {
-
- TypeDefinition attrType = attribute.AttributeType as TypeDefinition;
- if (attrType != null && !IsPublic (attrType))
- continue;
- if (slashdocFormatter.GetName (attribute.AttributeType) == null)
- continue;
-
- if (Array.IndexOf (IgnorableAttributes, attribute.AttributeType.FullName) >= 0)
- continue;
-
- StringList fields = new StringList ();
-
- for (int i = 0; i < attribute.ConstructorArguments.Count; ++i) {
- CustomAttributeArgument argument = attribute.ConstructorArguments [i];
- fields.Add (MakeAttributesValueString (
- argument.Value,
- argument.Type));
- }
- var namedArgs =
- (from namedArg in attribute.Fields
- select new { Type=namedArg.Argument.Type, Name=namedArg.Name, Value=namedArg.Argument.Value })
- .Concat (
- (from namedArg in attribute.Properties
- select new { Type=namedArg.Argument.Type, Name=namedArg.Name, Value=namedArg.Argument.Value }))
- .OrderBy (v => v.Name);
- foreach (var d in namedArgs)
- fields.Add (string.Format ("{0}={1}", d.Name,
- MakeAttributesValueString (d.Value, d.Type)));
-
- string a2 = String.Join(", ", fields.ToArray ());
- if (a2 != "") a2 = "(" + a2 + ")";
-
- string name = attribute.GetDeclaringType();
- if (name.EndsWith("Attribute")) name = name.Substring(0, name.Length-"Attribute".Length);
- yield return prefix + name + a2;
- }
- }
-
- static readonly string[] ValidExtensionMembers = {
- "Docs",
- "MemberSignature",
- "MemberType",
- "Parameters",
- "ReturnValue",
- "TypeParameters",
- };
-
- static readonly string[] ValidExtensionDocMembers = {
- "param",
- "summary",
- "typeparam",
- };
-
- private void UpdateExtensionMethods (XmlElement e, DocsNodeInfo info)
- {
- MethodDefinition me = info.Member as MethodDefinition;
- if (me == null)
- return;
- if (info.Parameters.Count < 1)
- return;
- if (!DocUtils.IsExtensionMethod (me))
- return;
-
- XmlNode em = e.OwnerDocument.CreateElement ("ExtensionMethod");
- XmlNode member = e.CloneNode (true);
- em.AppendChild (member);
- RemoveExcept (member, ValidExtensionMembers);
- RemoveExcept (member.SelectSingleNode ("Docs"), ValidExtensionDocMembers);
- WriteElementText (member, "MemberType", "ExtensionMethod");
- XmlElement link = member.OwnerDocument.CreateElement ("Link");
- var linktype = slashdocFormatter.GetName (me.DeclaringType);
- var linkmember = slashdocFormatter.GetDeclaration (me);
- link.SetAttribute ("Type", linktype);
- link.SetAttribute ("Member", linkmember);
- member.AppendChild (link);
- AddTargets (em, info);
-
- if (!IsMultiAssembly || (IsMultiAssembly && !extensionMethods.Any (ex => ex.SelectSingleNode ("Member/Link/@Type").Value == linktype && ex.SelectSingleNode ("Member/Link/@Member").Value == linkmember))) {
- extensionMethods.Add (em);
- }
- }
-
- private static void RemoveExcept (XmlNode node, string[] except)
- {
- if (node == null)
- return;
- MyXmlNodeList remove = null;
- foreach (XmlNode n in node.ChildNodes) {
- if (Array.BinarySearch (except, n.Name) < 0) {
- if (remove == null)
- remove = new MyXmlNodeList ();
- remove.Add (n);
- }
- }
- if (remove != null)
- foreach (XmlNode n in remove)
- node.RemoveChild (n);
- }
-
- private static void AddTargets (XmlNode member, DocsNodeInfo info)
- {
- XmlElement targets = member.OwnerDocument.CreateElement ("Targets");
- member.PrependChild (targets);
- if (!(info.Parameters [0].ParameterType is GenericParameter)) {
- var reference = info.Parameters[0].ParameterType;
- TypeReference typeReference = reference as TypeReference;
- var declaration = reference != null ?
- slashdocFormatter.GetDeclaration (typeReference) :
- slashdocFormatter.GetDeclaration (reference);
-
- AppendElementAttributeText (targets, "Target", "Type", declaration);
- }
- else {
- GenericParameter gp = (GenericParameter) info.Parameters [0].ParameterType;
- IList<TypeReference> constraints = gp.Constraints;
- if (constraints.Count == 0)
- AppendElementAttributeText (targets, "Target", "Type", "System.Object");
- else
- foreach (TypeReference c in constraints)
- AppendElementAttributeText(targets, "Target", "Type",
- slashdocFormatter.GetDeclaration (c));
- }
- }
-
- private static bool GetFieldConstValue (FieldDefinition field, out string value)
- {
- value = null;
- TypeDefinition type = field.DeclaringType.Resolve ();
- if (type != null && type.IsEnum) return false;
-
- if (type != null && type.IsGenericType ()) return false;
- if (!field.HasConstant)
- return false;
- if (field.IsLiteral) {
- object val = field.Constant;
- if (val == null) value = "null";
- else if (val is Enum) value = val.ToString();
- else if (val is IFormattable) {
- value = ((IFormattable)val).ToString(null, CultureInfo.InvariantCulture);
- if (val is string)
- value = "\"" + value + "\"";
- }
- if (value != null && value != "")
- return true;
- }
- return false;
- }
-
- // XML HELPER FUNCTIONS
-
- internal static XmlElement WriteElement(XmlNode parent, string element, bool forceNewElement = false) {
- XmlElement ret = (XmlElement)parent.SelectSingleNode(element);
- if (ret == null || forceNewElement) {
- string[] path = element.Split('/');
- foreach (string p in path) {
- ret = (XmlElement)parent.SelectSingleNode(p);
- if (ret == null || forceNewElement) {
- string ename = p;
- if (ename.IndexOf('[') >= 0) // strip off XPath predicate
- ename = ename.Substring(0, ename.IndexOf('['));
- ret = parent.OwnerDocument.CreateElement(ename);
- parent.AppendChild(ret);
- parent = ret;
- } else {
- parent = ret;
- }
- }
- }
- return ret;
- }
- private static XmlElement WriteElementText(XmlNode parent, string element, string value, bool forceNewElement = false) {
- XmlElement node = WriteElement(parent, element, forceNewElement: forceNewElement);
- node.InnerText = value;
- return node;
- }
-
- static XmlElement AppendElementText (XmlNode parent, string element, string value)
- {
- XmlElement n = parent.OwnerDocument.CreateElement (element);
- parent.AppendChild (n);
- n.InnerText = value;
- return n;
- }
-
- static XmlElement AppendElementAttributeText (XmlNode parent, string element, string attribute, string value)
- {
- XmlElement n = parent.OwnerDocument.CreateElement (element);
- parent.AppendChild (n);
- n.SetAttribute (attribute, value);
- return n;
- }
-
- internal static XmlNode CopyNode (XmlNode source, XmlNode dest)
- {
- XmlNode copy = dest.OwnerDocument.ImportNode (source, true);
- dest.AppendChild (copy);
- return copy;
- }
-
- private static void WriteElementInitialText(XmlElement parent, string element, string value) {
- XmlElement node = (XmlElement)parent.SelectSingleNode(element);
- if (node != null)
- return;
- node = WriteElement(parent, element);
- node.InnerText = value;
- }
- private static XmlElement WriteElementAttribute(XmlElement parent, string element, string attribute, string value, bool forceNewElement = false) {
- XmlElement node = WriteElement(parent, element, forceNewElement:forceNewElement);
- return WriteElementAttribute (parent, node, attribute, value);
- }
- private static XmlElement WriteElementAttribute(XmlElement parent, XmlElement node, string attribute, string value) {
- if (node.GetAttribute (attribute) != value) {
- node.SetAttribute (attribute, value);
- }
- return node;
- }
- internal static void ClearElement(XmlElement parent, string name) {
- XmlElement node = (XmlElement)parent.SelectSingleNode(name);
- if (node != null)
- parent.RemoveChild(node);
- }
-
- // DOCUMENTATION HELPER FUNCTIONS
-
- private void MakeDocNode (DocsNodeInfo info, IEnumerable<DocumentationImporter> setimporters)
- {
- List<GenericParameter> genericParams = info.GenericParameters;
- IList<ParameterDefinition> parameters = info.Parameters;
- TypeReference returntype = info.ReturnType;
- bool returnisreturn = info.ReturnIsReturn;
- XmlElement e = info.Node;
- bool addremarks = info.AddRemarks;
-
- WriteElementInitialText(e, "summary", "To be added.");
-
- if (parameters != null) {
- string[] values = new string [parameters.Count];
- for (int i = 0; i < values.Length; ++i)
- values [i] = parameters [i].Name;
- UpdateParameters (e, "param", values);
- }
-
- if (genericParams != null) {
- string[] values = new string [genericParams.Count];
- for (int i = 0; i < values.Length; ++i)
- values [i] = genericParams [i].Name;
- UpdateParameters (e, "typeparam", values);
- }
-
- string retnodename = null;
- if (returntype != null && returntype.FullName != "System.Void") { // FIXME
- retnodename = returnisreturn ? "returns" : "value";
- string retnodename_other = !returnisreturn ? "returns" : "value";
-
- // If it has a returns node instead of a value node, change its name.
- XmlElement retother = (XmlElement)e.SelectSingleNode(retnodename_other);
- if (retother != null) {
- XmlElement retnode = e.OwnerDocument.CreateElement(retnodename);
- foreach (XmlNode node in retother)
- retnode.AppendChild(node.CloneNode(true));
- e.ReplaceChild(retnode, retother);
- } else {
- WriteElementInitialText(e, retnodename, "To be added.");
- }
- } else {
- ClearElement(e, "returns");
- ClearElement(e, "value");
- }
-
- if (addremarks)
- WriteElementInitialText(e, "remarks", "To be added.");
-
- if (exceptions.HasValue && info.Member != null &&
- (exceptions.Value & ExceptionLocations.AddedMembers) == 0) {
- UpdateExceptions (e, info.Member);
- }
-
- foreach (DocumentationImporter importer in importers) {
- importer.ImportDocumentation (info);
- }
- if (setimporters != null) {
- foreach (var i in setimporters)
- i.ImportDocumentation (info);
- }
-
- OrderDocsNodes (e, e.ChildNodes);
- NormalizeWhitespace(e);
- }
-
- static readonly string[] DocsNodeOrder = {
- "typeparam", "param", "summary", "returns", "value", "remarks",
- };
-
- private static void OrderDocsNodes (XmlNode docs, XmlNodeList children)
- {
- ReorderNodes (docs, children, DocsNodeOrder);
- }
-
-
- private void UpdateParameters (XmlElement e, string element, string[] values)
- {
- if (values != null) {
- XmlNode[] paramnodes = new XmlNode[values.Length];
-
- // Some documentation had param nodes with leading spaces.
- foreach (XmlElement paramnode in e.SelectNodes(element)){
- paramnode.SetAttribute("name", paramnode.GetAttribute("name").Trim());
- }
-
- // If a member has only one parameter, we can track changes to
- // the name of the parameter easily.
- if (values.Length == 1 && e.SelectNodes(element).Count == 1) {
- UpdateParameterName (e, (XmlElement) e.SelectSingleNode(element), values [0]);
- }
-
- bool reinsert = false;
-
- // Pick out existing and still-valid param nodes, and
- // create nodes for parameters not in the file.
- Hashtable seenParams = new Hashtable();
- for (int pi = 0; pi < values.Length; pi++) {
- string p = values [pi];
- seenParams[p] = pi;
-
- paramnodes[pi] = e.SelectSingleNode(element + "[@name='" + p + "']");
- if (paramnodes[pi] != null) continue;
-
- XmlElement pe = e.OwnerDocument.CreateElement(element);
- pe.SetAttribute("name", p);
- pe.InnerText = "To be added.";
- paramnodes[pi] = pe;
- reinsert = true;
- }
-
- // Remove parameters that no longer exist and check all params are in the right order.
- int idx = 0;
- MyXmlNodeList todelete = new MyXmlNodeList ();
- foreach (XmlElement paramnode in e.SelectNodes(element)) {
- string name = paramnode.GetAttribute("name");
- if (!seenParams.ContainsKey(name)) {
- if (!delete && !paramnode.InnerText.StartsWith("To be added")) {
- Warning ("The following param node can only be deleted if the --delete option is given: ");
- if (e.ParentNode == e.OwnerDocument.DocumentElement) {
- // delegate type
- Warning ("\tXPath=/Type[@FullName=\"{0}\"]/Docs/param[@name=\"{1}\"]",
- e.OwnerDocument.DocumentElement.GetAttribute ("FullName"),
- name);
- }
- else {
- Warning ("\tXPath=/Type[@FullName=\"{0}\"]//Member[@MemberName=\"{1}\"]/Docs/param[@name=\"{2}\"]",
- e.OwnerDocument.DocumentElement.GetAttribute ("FullName"),
- e.ParentNode.Attributes ["MemberName"].Value,
- name);
- }
- Warning ("\tValue={0}", paramnode.OuterXml);
- } else {
- todelete.Add (paramnode);
- }
- continue;
- }
-
- if ((int)seenParams[name] != idx)
- reinsert = true;
-
- idx++;
- }
-
- foreach (XmlNode n in todelete) {
- n.ParentNode.RemoveChild (n);
- }
-
- // Re-insert the parameter nodes at the top of the doc section.
- if (reinsert)
- for (int pi = values.Length-1; pi >= 0; pi--)
- e.PrependChild(paramnodes[pi]);
- } else {
- // Clear all existing param nodes
- foreach (XmlNode paramnode in e.SelectNodes(element)) {
- if (!delete && !paramnode.InnerText.StartsWith("To be added")) {
- Console.WriteLine("The following param node can only be deleted if the --delete option is given:");
- Console.WriteLine(paramnode.OuterXml);
- } else {
- paramnode.ParentNode.RemoveChild(paramnode);
- }
- }
- }
- }
-
- private static void UpdateParameterName (XmlElement docs, XmlElement pe, string newName)
- {
- string existingName = pe.GetAttribute ("name");
- pe.SetAttribute ("name", newName);
- if (existingName == newName)
- return;
- foreach (XmlElement paramref in docs.SelectNodes (".//paramref"))
- if (paramref.GetAttribute ("name").Trim () == existingName)
- paramref.SetAttribute ("name", newName);
- }
-
- class CrefComparer : XmlNodeComparer {
-
- public CrefComparer ()
- {
- }
-
- public override int Compare (XmlNode x, XmlNode y)
- {
- string xType = x.Attributes ["cref"].Value;
- string yType = y.Attributes ["cref"].Value;
- string xNamespace = GetNamespace (xType);
- string yNamespace = GetNamespace (yType);
-
- int c = xNamespace.CompareTo (yNamespace);
- if (c != 0)
- return c;
- return xType.CompareTo (yType);
- }
-
- static string GetNamespace (string type)
- {
- int n = type.LastIndexOf ('.');
- if (n >= 0)
- return type.Substring (0, n);
- return string.Empty;
- }
- }
-
- private void UpdateExceptions (XmlNode docs, MemberReference member)
- {
- string indent = new string (' ', 10);
- foreach (var source in new ExceptionLookup (exceptions.Value)[member]) {
- string cref = slashdocFormatter.GetDeclaration (source.Exception);
- var node = docs.SelectSingleNode ("exception[@cref='" + cref + "']");
- if (node != null)
- continue;
- XmlElement e = docs.OwnerDocument.CreateElement ("exception");
- e.SetAttribute ("cref", cref);
- e.InnerXml = "To be added; from:\n" + indent + "<see cref=\"" +
- string.Join ("\" />,\n" + indent + "<see cref=\"",
- source.Sources.Select (m => slashdocFormatter.GetDeclaration (m))
- .OrderBy (s => s)) +
- "\" />";
- docs.AppendChild (e);
- }
- SortXmlNodes (docs, docs.SelectNodes ("exception"),
- new CrefComparer ());
- }
-
- private static void NormalizeWhitespace(XmlElement e) {
- // Remove all text and whitespace nodes from the element so it
- // is outputted with nice indentation and no blank lines.
- ArrayList deleteNodes = new ArrayList();
- foreach (XmlNode n in e)
- if (n is XmlText || n is XmlWhitespace || n is XmlSignificantWhitespace)
- deleteNodes.Add(n);
- foreach (XmlNode n in deleteNodes)
- n.ParentNode.RemoveChild(n);
- }
-
- private bool UpdateAssemblyVersions (XmlElement root, MemberReference member, bool add)
- {
- TypeDefinition type = member as TypeDefinition;
- if (type == null)
- type = member.DeclaringType as TypeDefinition;
-
- var versions = new string[] { GetAssemblyVersion (type.Module.Assembly) };
-
- if (root.LocalName == "AssemblyInfo")
- return UpdateAssemblyVersionForAssemblyInfo (root, root.ParentNode as XmlElement, versions, add: true);
- else
- return UpdateAssemblyVersions (root, type.Module.Assembly, versions, add);
- }
-
- private static string GetAssemblyVersion (AssemblyDefinition assembly)
- {
- return assembly.Name.Version.ToString();
- }
-
- private bool UpdateAssemblyVersions(XmlElement root, AssemblyDefinition assembly, string[] assemblyVersions, bool add)
- {
- if (IsMultiAssembly)
- return false;
-
- XmlElement av = (XmlElement) root.SelectSingleNode ("AssemblyVersions");
- if (av != null) {
- // AssemblyVersions is not part of the spec
- root.RemoveChild (av);
- }
-
- string oldNodeFilter = "AssemblyInfo[not(@apistyle) or @apistyle='classic']";
- string newNodeFilter = "AssemblyInfo[@apistyle='unified']";
- string thisNodeFilter = MDocUpdater.HasDroppedNamespace (assembly) ? newNodeFilter : oldNodeFilter;
- string thatNodeFilter = MDocUpdater.HasDroppedNamespace (assembly) ? oldNodeFilter : newNodeFilter;
-
- XmlElement e = (XmlElement) root.SelectSingleNode (thisNodeFilter);
- if (e == null) {
- e = root.OwnerDocument.CreateElement("AssemblyInfo");
-
- if (MDocUpdater.HasDroppedNamespace (assembly)) {
- e.AddApiStyle (ApiStyle.Unified);
- }
-
- root.AppendChild(e);
- }
-
- var thatNode = (XmlElement) root.SelectSingleNode (thatNodeFilter);
- if (MDocUpdater.HasDroppedNamespace (assembly) && thatNode != null) {
- // there's a classic node, we should add apistyles
- e.AddApiStyle (ApiStyle.Unified);
- thatNode.AddApiStyle (ApiStyle.Classic);
- }
-
- return UpdateAssemblyVersionForAssemblyInfo (e, root, assemblyVersions, add);
- }
-
- static bool UpdateAssemblyVersionForAssemblyInfo (XmlElement e, XmlElement root, string[] assemblyVersions, bool add)
- {
- List<XmlNode> matches = e.SelectNodes ("AssemblyVersion").Cast<XmlNode> ().Where (v => Array.IndexOf (assemblyVersions, v.InnerText) >= 0).ToList ();
- // matches.Count > 0 && add: ignore -- already present
- if (matches.Count > 0 && !add) {
- foreach (XmlNode c in matches)
- e.RemoveChild (c);
- }
- else if (matches.Count == 0 && add) {
- foreach (string sv in assemblyVersions) {
- XmlElement c = root.OwnerDocument.CreateElement("AssemblyVersion");
- c.InnerText = sv;
- e.AppendChild(c);
- }
- }
-
- // matches.Count == 0 && !add: ignore -- already not present
- XmlNodeList avs = e.SelectNodes ("AssemblyVersion");
- SortXmlNodes (e, avs, new VersionComparer ());
-
- bool anyNodesLeft = avs.Count != 0;
- if (!anyNodesLeft) {
- e.ParentNode.RemoveChild (e);
- }
- return anyNodesLeft;
- }
-
- // FIXME: get TypeReferences instead of string comparison?
- private static string[] IgnorableAttributes = {
- // Security related attributes
- "System.Reflection.AssemblyKeyFileAttribute",
- "System.Reflection.AssemblyDelaySignAttribute",
- // Present in @RefType
- "System.Runtime.InteropServices.OutAttribute",
- // For naming the indexer to use when not using indexers
- "System.Reflection.DefaultMemberAttribute",
- // for decimal constants
- "System.Runtime.CompilerServices.DecimalConstantAttribute",
- // compiler generated code
- "System.Runtime.CompilerServices.CompilerGeneratedAttribute",
- // more compiler generated code, e.g. iterator methods
- "System.Diagnostics.DebuggerHiddenAttribute",
- "System.Runtime.CompilerServices.FixedBufferAttribute",
- "System.Runtime.CompilerServices.UnsafeValueTypeAttribute",
- // extension methods
- "System.Runtime.CompilerServices.ExtensionAttribute",
- // Used to differentiate 'object' from C#4 'dynamic'
- "System.Runtime.CompilerServices.DynamicAttribute",
- };
-
- private IEnumerable<char> FilterSpecialChars (string value)
- {
- foreach (char c in value) {
- switch (c) {
- case '\0':
- yield return '\\';
- yield return '0';
- break;
- case '\t':
- yield return '\\';
- yield return 't';
- break;
- case '\n':
- yield return '\\';
- yield return 'n';
- break;
- case '\r':
- yield return '\\';
- yield return 'r';
- break;
- case '\f':
- yield return '\\';
- yield return 'f';
- break;
- case '\b':
- yield return '\\';
- yield return 'b';
- break;
- default:
- yield return c;
- break;
- }
- }
- }
-
- private void MakeAttributes (XmlElement root, IEnumerable<string> attributes, TypeReference t=null)
- {
- if (!attributes.Any ()) {
- ClearElement (root, "Attributes");
- return;
- }
-
- XmlElement e = (XmlElement)root.SelectSingleNode("Attributes");
- if (e != null)
- e.RemoveAll();
- else if (e == null)
- e = root.OwnerDocument.CreateElement("Attributes");
-
-
- foreach (string attribute in attributes) {
- XmlElement ae = root.OwnerDocument.CreateElement("Attribute");
- e.AppendChild(ae);
- var value = new String (FilterSpecialChars (attribute).ToArray ());
- WriteElementText(ae, "AttributeName", value);
- }
-
- if (e.ParentNode == null)
- root.AppendChild(e);
-
- NormalizeWhitespace(e);
- }
-
- public static string MakeAttributesValueString (object v, TypeReference valueType)
- {
- var formatters = new [] {
- new AttributeValueFormatter (),
- new ApplePlatformEnumFormatter (),
- new StandardFlagsEnumFormatter (),
- new DefaultAttributeValueFormatter (),
- };
-
- ResolvedTypeInfo type = new ResolvedTypeInfo (valueType);
- foreach (var formatter in formatters) {
- string formattedValue;
- if (formatter.TryFormatValue (v, type, out formattedValue)) {
- return formattedValue;
- }
- }
-
- // this should never occur because the DefaultAttributeValueFormatter will always
- // successfully format the value ... but this is needed to satisfy the compiler :)
- throw new InvalidDataException (string.Format ("Unable to format attribute value ({0})", v.ToString ()));
- }
-
- internal static IDictionary<long, string> GetEnumerationValues (TypeDefinition type)
- {
- var values = new Dictionary<long, string> ();
- foreach (var f in
- (from f in type.Fields
- where !(f.IsRuntimeSpecialName || f.IsSpecialName)
- select f)) {
- values [ToInt64 (f.Constant)] = f.Name;
- }
- return values;
- }
-
- internal static long ToInt64 (object value)
- {
- if (value is ulong)
- return (long) (ulong) value;
- return Convert.ToInt64 (value);
- }
-
- private void MakeParameters (XmlElement root, MemberReference member, IList<ParameterDefinition> parameters, bool shouldDuplicateWithNew=false)
- {
- XmlElement e = WriteElement(root, "Parameters");
-
- int i = 0;
- foreach (ParameterDefinition p in parameters) {
- XmlElement pe;
-
- // param info
- var ptype = GetDocParameterType (p.ParameterType);
- var newPType = ptype;
-
- if (MDocUpdater.SwitchingToMagicTypes) {
- newPType = NativeTypeManager.ConvertFromNativeType (ptype);
- }
-
- // now find the existing node, if it's there so we can reuse it.
- var nodes = root.SelectSingleNode ("Parameters").SelectNodes ("Parameter")
- .Cast<XmlElement> ().Where (x => x.GetAttribute ("Name") == p.Name)
- .ToArray();
-
- if (nodes.Count () == 0) {
- // wasn't found, let's make sure it wasn't just cause the param name was changed
- nodes = root.SelectSingleNode ("Parameters").SelectNodes ("Parameter")
- .Cast<XmlElement> ()
- .Skip (i) // this makes sure we don't inadvertently "reuse" nodes when adding new ones
- .Where (x => x.GetAttribute ("Name") != p.Name && (x.GetAttribute ("Type") == ptype || x.GetAttribute ("Type") == newPType))
- .Take(1) // there might be more than one that meets this parameter ... only take the first.
- .ToArray();
- }
-
- AddXmlNode (nodes,
- x => x.GetAttribute ("Type") == ptype,
- x => x.SetAttribute ("Type", ptype),
- () => {
- pe = root.OwnerDocument.CreateElement ("Parameter");
- e.AppendChild (pe);
-
- pe.SetAttribute ("Name", p.Name);
- pe.SetAttribute ("Type", ptype);
- if (p.ParameterType is ByReferenceType) {
- if (p.IsOut)
- pe.SetAttribute ("RefType", "out");
- else
- pe.SetAttribute ("RefType", "ref");
- }
-
- MakeAttributes (pe, GetCustomAttributes (p.CustomAttributes, ""));
- return pe;
- },
- member);
-
- i++;
- }
- }
-
- private void MakeTypeParameters (XmlElement root, IList<GenericParameter> typeParams, MemberReference member, bool shouldDuplicateWithNew)
- {
- if (typeParams == null || typeParams.Count == 0) {
- XmlElement f = (XmlElement) root.SelectSingleNode ("TypeParameters");
- if (f != null)
- root.RemoveChild (f);
- return;
- }
- XmlElement e = WriteElement(root, "TypeParameters");
-
- var nodes = e.SelectNodes ("TypeParameter").Cast<XmlElement> ().ToArray ();
-
- foreach (GenericParameter t in typeParams) {
-
- IList<TypeReference> constraints = t.Constraints;
- GenericParameterAttributes attrs = t.Attributes;
-
-
- AddXmlNode (
- nodes,
- x => {
- var baseType = e.SelectSingleNode("BaseTypeName");
- // TODO: should this comparison take into account BaseTypeName?
- return x.GetAttribute("Name") == t.Name;
- },
- x => {}, // no additional action required
- () => {
-
- XmlElement pe = root.OwnerDocument.CreateElement("TypeParameter");
- e.AppendChild(pe);
- pe.SetAttribute("Name", t.Name);
- MakeAttributes (pe, GetCustomAttributes (t.CustomAttributes, ""), t.DeclaringType);
- XmlElement ce = (XmlElement) e.SelectSingleNode ("Constraints");
- if (attrs == GenericParameterAttributes.NonVariant && constraints.Count == 0) {
- if (ce != null)
- e.RemoveChild (ce);
- return pe;
- }
- if (ce != null)
- ce.RemoveAll();
- else {
- ce = root.OwnerDocument.CreateElement ("Constraints");
- }
- pe.AppendChild (ce);
- if ((attrs & GenericParameterAttributes.Contravariant) != 0)
- AppendElementText (ce, "ParameterAttribute", "Contravariant");
- if ((attrs & GenericParameterAttributes.Covariant) != 0)
- AppendElementText (ce, "ParameterAttribute", "Covariant");
- if ((attrs & GenericParameterAttributes.DefaultConstructorConstraint) != 0)
- AppendElementText (ce, "ParameterAttribute", "DefaultConstructorConstraint");
- if ((attrs & GenericParameterAttributes.NotNullableValueTypeConstraint) != 0)
- AppendElementText (ce, "ParameterAttribute", "NotNullableValueTypeConstraint");
- if ((attrs & GenericParameterAttributes.ReferenceTypeConstraint) != 0)
- AppendElementText (ce, "ParameterAttribute", "ReferenceTypeConstraint");
- foreach (TypeReference c in constraints) {
- TypeDefinition cd = c.Resolve ();
- AppendElementText (ce,
- (cd != null && cd.IsInterface) ? "InterfaceName" : "BaseTypeName",
- GetDocTypeFullName (c));
- }
-
- return pe;
- },
- member);
- }
- }
-
- private void MakeParameters (XmlElement root, MemberReference mi, bool shouldDuplicateWithNew)
- {
- if (mi is MethodDefinition && ((MethodDefinition) mi).IsConstructor)
- MakeParameters (root, mi, ((MethodDefinition)mi).Parameters, shouldDuplicateWithNew);
- else if (mi is MethodDefinition) {
- MethodDefinition mb = (MethodDefinition) mi;
- IList<ParameterDefinition> parameters = mb.Parameters;
- MakeParameters(root, mi, parameters, shouldDuplicateWithNew);
- if (parameters.Count > 0 && DocUtils.IsExtensionMethod (mb)) {
- XmlElement p = (XmlElement) root.SelectSingleNode ("Parameters/Parameter[position()=1]");
- p.SetAttribute ("RefType", "this");
- }
- }
- else if (mi is PropertyDefinition) {
- IList<ParameterDefinition> parameters = ((PropertyDefinition)mi).Parameters;
- if (parameters.Count > 0)
- MakeParameters(root, mi, parameters, shouldDuplicateWithNew);
- else
- return;
- }
- else if (mi is FieldDefinition) return;
- else if (mi is EventDefinition) return;
- else throw new ArgumentException();
- }
-
- internal static string GetDocParameterType (TypeReference type)
- {
- return GetDocTypeFullName (type).Replace ("@", "&");
- }
-
- private void MakeReturnValue (XmlElement root, TypeReference type, IList<CustomAttribute> attributes, bool shouldDuplicateWithNew=false)
- {
- XmlElement e = WriteElement(root, "ReturnValue");
- var valueToUse = GetDocTypeFullName (type);
-
- AddXmlNode (e.SelectNodes("ReturnType").Cast<XmlElement> ().ToArray (),
- x => x.InnerText == valueToUse,
- x => x.InnerText = valueToUse,
- () => {
- var newNode = WriteElementText(e, "ReturnType", valueToUse, forceNewElement: true);
- if (attributes != null)
- MakeAttributes(e, GetCustomAttributes (attributes, ""), type);
-
- return newNode;
- },
- type);
- }
-
- private void MakeReturnValue (XmlElement root, MemberReference mi, bool shouldDuplicateWithNew=false)
- {
- if (mi is MethodDefinition && ((MethodDefinition) mi).IsConstructor)
- return;
- else if (mi is MethodDefinition)
- MakeReturnValue (root, ((MethodDefinition)mi).ReturnType, ((MethodDefinition)mi).MethodReturnType.CustomAttributes, shouldDuplicateWithNew);
- else if (mi is PropertyDefinition)
- MakeReturnValue (root, ((PropertyDefinition)mi).PropertyType, null, shouldDuplicateWithNew);
- else if (mi is FieldDefinition)
- MakeReturnValue (root, ((FieldDefinition)mi).FieldType, null, shouldDuplicateWithNew);
- else if (mi is EventDefinition)
- MakeReturnValue (root, ((EventDefinition)mi).EventType, null, shouldDuplicateWithNew);
- else
- throw new ArgumentException(mi + " is a " + mi.GetType().FullName);
- }
-
- private XmlElement MakeMember(XmlDocument doc, DocsNodeInfo info, XmlNode members, FrameworkTypeEntry typeEntry)
- {
- MemberReference mi = info.Member;
- if (mi is TypeDefinition) return null;
-
- string sigs = memberFormatters [0].GetDeclaration (mi);
- if (sigs == null) return null; // not publicly visible
-
- // no documentation for property/event accessors. Is there a better way of doing this?
- if (mi.Name.StartsWith("get_", StringComparison.Ordinal)) return null;
- if (mi.Name.StartsWith("set_", StringComparison.Ordinal)) return null;
- if (mi.Name.StartsWith("add_", StringComparison.Ordinal)) return null;
- if (mi.Name.StartsWith("remove_", StringComparison.Ordinal)) return null;
- if (mi.Name.StartsWith("raise_", StringComparison.Ordinal)) return null;
-
- XmlElement me = doc.CreateElement("Member");
- members.AppendChild (me);
- me.SetAttribute("MemberName", GetMemberName (mi));
-
- info.Node = me;
- UpdateMember(info, typeEntry);
- if (exceptions.HasValue &&
- (exceptions.Value & ExceptionLocations.AddedMembers) != 0)
- UpdateExceptions (info.Node, info.Member);
-
- if (since != null) {
- XmlNode docs = me.SelectSingleNode("Docs");
- docs.AppendChild (CreateSinceNode (doc));
- }
-
- return me;
- }
-
- internal static string GetMemberName (MemberReference mi)
- {
- MethodDefinition mb = mi as MethodDefinition;
- if (mb == null) {
- PropertyDefinition pi = mi as PropertyDefinition;
- if (pi == null)
- return mi.Name;
- return DocUtils.GetPropertyName (pi);
- }
- StringBuilder sb = new StringBuilder (mi.Name.Length);
- if (!DocUtils.IsExplicitlyImplemented (mb))
- sb.Append (mi.Name);
- else {
- TypeReference iface;
- MethodReference ifaceMethod;
- DocUtils.GetInfoForExplicitlyImplementedMethod (mb, out iface, out ifaceMethod);
- sb.Append (GetDocTypeFullName (iface));
- sb.Append ('.');
- sb.Append (ifaceMethod.Name);
- }
- if (mb.IsGenericMethod ()) {
- IList<GenericParameter> typeParams = mb.GenericParameters;
- if (typeParams.Count > 0) {
- sb.Append ("<");
- sb.Append (typeParams [0].Name);
- for (int i = 1; i < typeParams.Count; ++i)
- sb.Append (",").Append (typeParams [i].Name);
- sb.Append (">");
- }
- }
- return sb.ToString ();
- }
-
- /// SIGNATURE GENERATION FUNCTIONS
- internal static bool IsPrivate (MemberReference mi)
- {
- return memberFormatters [0].GetDeclaration (mi) == null;
- }
-
- internal static string GetMemberType (MemberReference mi)
- {
- if (mi is MethodDefinition && ((MethodDefinition) mi).IsConstructor)
- return "Constructor";
- if (mi is MethodDefinition)
- return "Method";
- if (mi is PropertyDefinition)
- return "Property";
- if (mi is FieldDefinition)
- return "Field";
- if (mi is EventDefinition)
- return "Event";
- throw new ArgumentException();
- }
-
- private static string GetDocTypeName (TypeReference type)
- {
- return docTypeFormatter.GetName (type);
- }
-
- internal static string GetDocTypeFullName (TypeReference type)
- {
- return DocTypeFullMemberFormatter.Default.GetName (type);
- }
-
- internal static string GetXPathForMember (DocumentationMember member)
- {
- StringBuilder xpath = new StringBuilder ();
- xpath.Append ("//Members/Member[@MemberName=\"")
- .Append (member.MemberName)
- .Append ("\"]");
- if (member.Parameters != null && member.Parameters.Count > 0) {
- xpath.Append ("/Parameters[count(Parameter) = ")
- .Append (member.Parameters.Count);
- for (int i = 0; i < member.Parameters.Count; ++i) {
- xpath.Append (" and Parameter [").Append (i+1).Append ("]/@Type=\"");
- xpath.Append (member.Parameters [i]);
- xpath.Append ("\"");
- }
- xpath.Append ("]/..");
- }
- return xpath.ToString ();
- }
-
- public static string GetXPathForMember (XPathNavigator member)
- {
- StringBuilder xpath = new StringBuilder ();
- xpath.Append ("//Type[@FullName=\"")
- .Append (member.SelectSingleNode ("../../@FullName").Value)
- .Append ("\"]/");
- xpath.Append ("Members/Member[@MemberName=\"")
- .Append (member.SelectSingleNode ("@MemberName").Value)
- .Append ("\"]");
- XPathNodeIterator parameters = member.Select ("Parameters/Parameter");
- if (parameters.Count > 0) {
- xpath.Append ("/Parameters[count(Parameter) = ")
- .Append (parameters.Count);
- int i = 0;
- while (parameters.MoveNext ()) {
- ++i;
- xpath.Append (" and Parameter [").Append (i).Append ("]/@Type=\"");
- xpath.Append (parameters.Current.Value);
- xpath.Append ("\"");
- }
- xpath.Append ("]/..");
- }
- return xpath.ToString ();
- }
-
- public static string GetXPathForMember (MemberReference member)
- {
- StringBuilder xpath = new StringBuilder ();
- xpath.Append ("//Type[@FullName=\"")
- .Append (member.DeclaringType.FullName)
- .Append ("\"]/");
- xpath.Append ("Members/Member[@MemberName=\"")
- .Append (GetMemberName (member))
- .Append ("\"]");
-
- IList<ParameterDefinition> parameters = null;
- if (member is MethodDefinition)
- parameters = ((MethodDefinition) member).Parameters;
- else if (member is PropertyDefinition) {
- parameters = ((PropertyDefinition) member).Parameters;
- }
- if (parameters != null && parameters.Count > 0) {
- xpath.Append ("/Parameters[count(Parameter) = ")
- .Append (parameters.Count);
- for (int i = 0; i < parameters.Count; ++i) {
- xpath.Append (" and Parameter [").Append (i+1).Append ("]/@Type=\"");
- xpath.Append (GetDocParameterType (parameters [i].ParameterType));
- xpath.Append ("\"");
- }
- xpath.Append ("]/..");
- }
- return xpath.ToString ();
- }
-}
-
-static class CecilExtensions {
- public static string GetDeclaringType(this CustomAttribute attribute)
- {
- var type = attribute.Constructor.DeclaringType;
- var typeName = type.FullName;
-
- string translatedType = NativeTypeManager.GetTranslatedName (type);
- return translatedType;
- }
-
- public static IEnumerable<MemberReference> GetMembers (this TypeDefinition type)
- {
- foreach (var c in type.Methods.Where (m => m.IsConstructor))
- yield return (MemberReference) c;
- foreach (var e in type.Events)
- yield return (MemberReference) e;
- foreach (var f in type.Fields)
- yield return (MemberReference) f;
- foreach (var m in type.Methods.Where (m => !m.IsConstructor))
- yield return (MemberReference) m;
- foreach (var t in type.NestedTypes)
- yield return (MemberReference) t;
- foreach (var p in type.Properties)
- yield return (MemberReference) p;
- }
-
- public static IEnumerable<MemberReference> GetMembers (this TypeDefinition type, string member)
- {
- return GetMembers (type).Where (m => m.Name == member);
- }
-
- public static MemberReference GetMember (this TypeDefinition type, string member)
- {
- return GetMembers (type, member).EnsureZeroOrOne ();
- }
-
- static T EnsureZeroOrOne<T> (this IEnumerable<T> source)
- {
- if (source.Count () > 1)
- throw new InvalidOperationException ("too many matches");
- return source.FirstOrDefault ();
- }
-
- public static MethodDefinition GetMethod (this TypeDefinition type, string method)
- {
- return type.Methods
- .Where (m => m.Name == method)
- .EnsureZeroOrOne ();
- }
-
- public static IEnumerable<MemberReference> GetDefaultMembers (this TypeReference type)
- {
- TypeDefinition def = type as TypeDefinition;
- if (def == null)
- return new MemberReference [0];
- CustomAttribute defMemberAttr = def.CustomAttributes
- .FirstOrDefault (c => c.AttributeType.FullName == "System.Reflection.DefaultMemberAttribute");
- if (defMemberAttr == null)
- return new MemberReference [0];
- string name = (string) defMemberAttr.ConstructorArguments [0].Value;
- return def.Properties
- .Where (p => p.Name == name)
- .Select (p => (MemberReference) p);
- }
-
- public static IEnumerable<TypeDefinition> GetTypes (this AssemblyDefinition assembly)
- {
- return assembly.Modules.SelectMany (md => md.GetAllTypes ());
- }
-
- public static TypeDefinition GetType (this AssemblyDefinition assembly, string type)
- {
- return GetTypes (assembly)
- .Where (td => td.FullName == type)
- .EnsureZeroOrOne ();
- }
-
- public static bool IsGenericType (this TypeReference type)
- {
- return type.GenericParameters.Count > 0;
- }
-
- public static bool IsGenericMethod (this MethodReference method)
- {
- return method.GenericParameters.Count > 0;
- }
-
- public static TypeReference GetUnderlyingType (this TypeDefinition type)
- {
- if (!type.IsEnum)
- return type;
- return type.Fields.First (f => f.Name == "value__").FieldType;
- }
-
- public static IEnumerable<TypeDefinition> GetAllTypes (this ModuleDefinition self)
- {
- return self.Types.SelectMany (t => t.GetAllTypes ());
- }
-
- static IEnumerable<TypeDefinition> GetAllTypes (this TypeDefinition self)
- {
- yield return self;
-
- if (!self.HasNestedTypes)
- yield break;
-
- foreach (var type in self.NestedTypes.SelectMany (t => t.GetAllTypes ()))
- yield return type;
- }
-}
-
-enum ApiStyle {
- Classic,
- Unified
-}
-
-static class DocUtils {
-
- public static bool DoesNotHaveApiStyle(this XmlElement element, ApiStyle style) {
- string styleString = style.ToString ().ToLowerInvariant ();
- string apistylevalue = element.GetAttribute ("apistyle");
- return apistylevalue != styleString || string.IsNullOrWhiteSpace(apistylevalue);
- }
- public static bool HasApiStyle(this XmlElement element, ApiStyle style) {
- string styleString = style.ToString ().ToLowerInvariant ();
- return element.GetAttribute ("apistyle") == styleString;
- }
- public static bool HasApiStyle(this XmlNode node, ApiStyle style)
- {
- var attribute = node.Attributes ["apistyle"];
- return attribute != null && attribute.Value == style.ToString ().ToLowerInvariant ();
- }
- public static void AddApiStyle(this XmlElement element, ApiStyle style) {
- string styleString = style.ToString ().ToLowerInvariant ();
- var existingValue = element.GetAttribute ("apistyle");
- if (string.IsNullOrWhiteSpace (existingValue) || existingValue != styleString) {
- element.SetAttribute ("apistyle", styleString);
- }
-
- // Propagate the API style up to the membernode if necessary
- if (element.LocalName == "AssemblyInfo" && element.ParentNode != null && element.ParentNode.LocalName == "Member") {
- var member = element.ParentNode;
- var unifiedAssemblyNode = member.SelectSingleNode ("AssemblyInfo[@apistyle='unified']");
- var classicAssemblyNode = member.SelectSingleNode ("AssemblyInfo[not(@apistyle) or @apistyle='classic']");
-
- var parentAttribute = element.ParentNode.Attributes ["apistyle"];
- Action removeStyle = () => element.ParentNode.Attributes.Remove (parentAttribute);
- Action propagateStyle = () => {
- if (parentAttribute == null) {
- // if it doesn't have the attribute, then add it
- parentAttribute = element.OwnerDocument.CreateAttribute ("apistyle");
- parentAttribute.Value = styleString;
- element.ParentNode.Attributes.Append (parentAttribute);
- }
- };
-
- if ((style == ApiStyle.Classic && unifiedAssemblyNode != null) || (style == ApiStyle.Unified && classicAssemblyNode != null))
- removeStyle ();
- else
- propagateStyle ();
- }
- }
- public static void AddApiStyle (this XmlNode node, ApiStyle style)
- {
- string styleString = style.ToString ().ToLowerInvariant ();
- var existingAttribute = node.Attributes ["apistyle"];
- if (existingAttribute == null) {
- existingAttribute = node.OwnerDocument.CreateAttribute ("apistyle");
- node.Attributes.Append (existingAttribute);
- }
- existingAttribute.Value = styleString;
- }
- public static void RemoveApiStyle (this XmlElement element, ApiStyle style)
- {
- string styleString = style.ToString ().ToLowerInvariant ();
- string existingValue = element.GetAttribute ("apistyle");
- if (string.IsNullOrWhiteSpace (existingValue) || existingValue == styleString) {
- element.RemoveAttribute ("apistyle");
- }
- }
- public static void RemoveApiStyle (this XmlNode node, ApiStyle style)
- {
- var styleAttribute = node.Attributes ["apistyle"];
- if (styleAttribute != null && styleAttribute.Value == style.ToString ().ToLowerInvariant ()) {
- node.Attributes.Remove (styleAttribute);
- }
- }
-
- public static bool IsExplicitlyImplemented (MethodDefinition method)
- {
- return method != null && method.IsPrivate && method.IsFinal && method.IsVirtual;
- }
-
- public static string GetTypeDotMember (string name)
- {
- int startType, startMethod;
- startType = startMethod = -1;
- for (int i = 0; i < name.Length; ++i) {
- if (name [i] == '.') {
- startType = startMethod;
- startMethod = i;
- }
- }
- return name.Substring (startType+1);
- }
-
- public static string GetMember (string name)
- {
- int i = name.LastIndexOf ('.');
- if (i == -1)
- return name;
- return name.Substring (i+1);
- }
-
- public static void GetInfoForExplicitlyImplementedMethod (
- MethodDefinition method, out TypeReference iface, out MethodReference ifaceMethod)
- {
- iface = null;
- ifaceMethod = null;
- if (method.Overrides.Count != 1)
- throw new InvalidOperationException ("Could not determine interface type for explicitly-implemented interface member " + method.Name);
- iface = method.Overrides [0].DeclaringType;
- ifaceMethod = method.Overrides [0];
- }
-
- public static string GetPropertyName (PropertyDefinition pi)
- {
- // Issue: (g)mcs-generated assemblies that explicitly implement
- // properties don't specify the full namespace, just the
- // TypeName.Property; .NET uses Full.Namespace.TypeName.Property.
- MethodDefinition method = pi.GetMethod;
- if (method == null)
- method = pi.SetMethod;
- if (!IsExplicitlyImplemented (method))
- return pi.Name;
-
- // Need to determine appropriate namespace for this member.
- TypeReference iface;
- MethodReference ifaceMethod;
- GetInfoForExplicitlyImplementedMethod (method, out iface, out ifaceMethod);
- return string.Join (".", new string[]{
- DocTypeFullMemberFormatter.Default.GetName (iface),
- GetMember (pi.Name)});
- }
-
- public static string GetNamespace (TypeReference type)
- {
- if (type.GetElementType ().IsNested)
- type = type.GetElementType ();
- while (type != null && type.IsNested)
- type = type.DeclaringType;
- if (type == null)
- return string.Empty;
-
- string typeNS = type.Namespace;
-
- // first, make sure this isn't a type reference to another assembly/module
-
- bool isInAssembly = MDocUpdater.IsInAssemblies(type.Module.Name);
- if (isInAssembly && !typeNS.StartsWith ("System") && MDocUpdater.HasDroppedNamespace (type)) {
- typeNS = string.Format ("{0}.{1}", MDocUpdater.droppedNamespace, typeNS);
- }
- return typeNS;
- }
-
- public static string PathCombine (string dir, string path)
- {
- if (dir == null)
- dir = "";
- if (path == null)
- path = "";
- return Path.Combine (dir, path);
- }
-
- public static bool IsExtensionMethod (MethodDefinition method)
- {
- return
- method.CustomAttributes
- .Any (m => m.AttributeType.FullName == "System.Runtime.CompilerServices.ExtensionAttribute")
- && method.DeclaringType.CustomAttributes
- .Any (m => m.AttributeType.FullName == "System.Runtime.CompilerServices.ExtensionAttribute");
- }
-
- public static bool IsDelegate (TypeDefinition type)
- {
- TypeReference baseRef = type.BaseType;
- if (baseRef == null)
- return false;
- return !type.IsAbstract && baseRef.FullName == "System.Delegate" || // FIXME
- baseRef.FullName == "System.MulticastDelegate";
- }
-
- public static List<TypeReference> GetDeclaringTypes (TypeReference type)
- {
- List<TypeReference> decls = new List<TypeReference> ();
- decls.Add (type);
- while (type.DeclaringType != null) {
- decls.Add (type.DeclaringType);
- type = type.DeclaringType;
- }
- decls.Reverse ();
- return decls;
- }
-
- public static int GetGenericArgumentCount (TypeReference type)
- {
- GenericInstanceType inst = type as GenericInstanceType;
- return inst != null
- ? inst.GenericArguments.Count
- : type.GenericParameters.Count;
- }
-
- public static IEnumerable<TypeReference> GetUserImplementedInterfaces (TypeDefinition type)
- {
- HashSet<string> inheritedInterfaces = GetInheritedInterfaces (type);
- List<TypeReference> userInterfaces = new List<TypeReference> ();
- foreach (var ii in type.Interfaces) {
- var iface = ii.InterfaceType;
- TypeReference lookup = iface.Resolve () ?? iface;
- if (!inheritedInterfaces.Contains (GetQualifiedTypeName (lookup)))
- userInterfaces.Add (iface);
- }
- return userInterfaces.Where (i => MDocUpdater.IsPublic (i.Resolve ()));
- }
-
- private static string GetQualifiedTypeName (TypeReference type)
- {
- return "[" + type.Scope.Name + "]" + type.FullName;
- }
-
- private static HashSet<string> GetInheritedInterfaces (TypeDefinition type)
- {
- HashSet<string> inheritedInterfaces = new HashSet<string> ();
- Action<TypeDefinition> a = null;
- a = t => {
- if (t == null) return;
- foreach (var r in t.Interfaces) {
- inheritedInterfaces.Add (GetQualifiedTypeName (r.InterfaceType));
- a (r.InterfaceType.Resolve ());
- }
- };
- TypeReference baseRef = type.BaseType;
- while (baseRef != null) {
- TypeDefinition baseDef = baseRef.Resolve ();
- if (baseDef != null) {
- a (baseDef);
- baseRef = baseDef.BaseType;
- }
- else
- baseRef = null;
- }
- foreach (var r in type.Interfaces)
- a (r.InterfaceType.Resolve ());
- return inheritedInterfaces;
- }
-}
-
-class DocsNodeInfo {
- public DocsNodeInfo (XmlElement node)
- {
- this.Node = node;
- }
-
- public DocsNodeInfo (XmlElement node, TypeDefinition type)
- : this (node)
- {
- SetType (type);
- }
-
- public DocsNodeInfo (XmlElement node, MemberReference member)
- : this (node)
- {
- SetMemberInfo (member);
- }
-
- void SetType (TypeDefinition type)
- {
- if (type == null)
- throw new ArgumentNullException ("type");
- Type = type;
- GenericParameters = new List<GenericParameter> (type.GenericParameters);
- List<TypeReference> declTypes = DocUtils.GetDeclaringTypes (type);
- int maxGenArgs = DocUtils.GetGenericArgumentCount (type);
- for (int i = 0; i < declTypes.Count - 1; ++i) {
- int remove = System.Math.Min (maxGenArgs,
- DocUtils.GetGenericArgumentCount (declTypes [i]));
- maxGenArgs -= remove;
- while (remove-- > 0)
- GenericParameters.RemoveAt (0);
- }
- if (DocUtils.IsDelegate (type)) {
- Parameters = type.GetMethod("Invoke").Parameters;
- ReturnType = type.GetMethod("Invoke").ReturnType;
- ReturnIsReturn = true;
- }
- }
-
- void SetMemberInfo (MemberReference member)
- {
- if (member == null)
- throw new ArgumentNullException ("member");
- ReturnIsReturn = true;
- AddRemarks = true;
- Member = member;
-
- if (member is MethodReference ) {
- MethodReference mr = (MethodReference) member;
- Parameters = mr.Parameters;
- if (mr.IsGenericMethod ()) {
- GenericParameters = new List<GenericParameter> (mr.GenericParameters);
- }
- }
- else if (member is PropertyDefinition) {
- Parameters = ((PropertyDefinition) member).Parameters;
- }
-
- if (member is MethodDefinition) {
- ReturnType = ((MethodDefinition) member).ReturnType;
- } else if (member is PropertyDefinition) {
- ReturnType = ((PropertyDefinition) member).PropertyType;
- ReturnIsReturn = false;
- }
-
- // no remarks section for enum members
- if (member.DeclaringType != null && ((TypeDefinition) member.DeclaringType).IsEnum)
- AddRemarks = false;
- }
-
- public TypeReference ReturnType;
- public List<GenericParameter> GenericParameters;
- public IList<ParameterDefinition> Parameters;
- public bool ReturnIsReturn;
- public XmlElement Node;
- public bool AddRemarks = true;
- public MemberReference Member;
- public TypeDefinition Type;
-
- public override string ToString ()
- {
- return string.Format ("{0} - {1} - {2}", Type, Member, Node == null ? "no xml" : "with xml");
- }
-}
-
-class DocumentationEnumerator {
-
- public virtual IEnumerable<TypeDefinition> GetDocumentationTypes (AssemblyDefinition assembly, List<string> forTypes)
- {
- return GetDocumentationTypes (assembly, forTypes, null);
- }
-
- protected IEnumerable<TypeDefinition> GetDocumentationTypes (AssemblyDefinition assembly, List<string> forTypes, HashSet<string> seen)
- {
- foreach (TypeDefinition type in assembly.GetTypes()) {
- if (forTypes != null && forTypes.BinarySearch (type.FullName) < 0)
- continue;
- if (seen != null && seen.Contains (type.FullName))
- continue;
- yield return type;
- foreach (TypeDefinition nested in type.NestedTypes)
- yield return nested;
- }
- }
-
- public virtual IEnumerable<DocsNodeInfo> GetDocumentationMembers (XmlDocument basefile, TypeDefinition type)
- {
- foreach (XmlElement oldmember in basefile.SelectNodes("Type/Members/Member")) {
- if (oldmember.GetAttribute ("__monodocer-seen__") == "true") {
- oldmember.RemoveAttribute ("__monodocer-seen__");
- continue;
- }
- MemberReference m = GetMember (type, new DocumentationMember (oldmember));
- if (m == null) {
- yield return new DocsNodeInfo (oldmember);
- }
- else {
- yield return new DocsNodeInfo (oldmember, m);
- }
- }
- }
-
- protected static MemberReference GetMember (TypeDefinition type, DocumentationMember member)
- {
- string membertype = member.MemberType;
-
- string returntype = member.ReturnType;
-
- string docName = member.MemberName;
-
- string[] docTypeParams = GetTypeParameters (docName, member.TypeParameters);
-
- // If we're using 'magic types', then we might get false positives ... in those cases, we keep searching
- MemberReference likelyCandidate = null;
-
- // Loop through all members in this type with the same name
- var reflectedMembers = GetReflectionMembers (type, docName).ToArray ();
- foreach (MemberReference mi in reflectedMembers) {
- bool matchedMagicType = false;
- if (mi is TypeDefinition) continue;
- if (MDocUpdater.GetMemberType(mi) != membertype) continue;
-
- if (MDocUpdater.IsPrivate (mi))
- continue;
-
- IList<ParameterDefinition> pis = null;
- string[] typeParams = null;
- if (mi is MethodDefinition) {
- MethodDefinition mb = (MethodDefinition) mi;
- pis = mb.Parameters;
- if (mb.IsGenericMethod ()) {
- IList<GenericParameter> args = mb.GenericParameters;
- typeParams = args.Select (p => p.Name).ToArray ();
- }
- }
- else if (mi is PropertyDefinition)
- pis = ((PropertyDefinition)mi).Parameters;
-
- // check type parameters
- int methodTcount = member.TypeParameters == null ? 0 : member.TypeParameters.Count;
- int reflectionTcount = typeParams == null ? 0 : typeParams.Length;
- if (methodTcount != reflectionTcount)
- continue;
-
- // check member parameters
- int mcount = member.Parameters == null ? 0 : member.Parameters.Count;
- int pcount = pis == null ? 0 : pis.Count;
- if (mcount != pcount)
- continue;
-
- MethodDefinition mDef = mi as MethodDefinition;
- if (mDef != null && !mDef.IsConstructor) {
- // Casting operators can overload based on return type.
- string rtype = GetReplacedString (
- MDocUpdater.GetDocTypeFullName (((MethodDefinition)mi).ReturnType),
- typeParams, docTypeParams);
- string originalRType = rtype;
- if (MDocUpdater.SwitchingToMagicTypes) {
- rtype = NativeTypeManager.ConvertFromNativeType (rtype);
-
- }
- if ((returntype != rtype && originalRType == rtype) ||
- (MDocUpdater.SwitchingToMagicTypes && returntype != originalRType && returntype != rtype && originalRType != rtype)) {
- continue;
- }
-
- if (originalRType != rtype)
- matchedMagicType = true;
- }
-
- if (pcount == 0)
- return mi;
- bool good = true;
- for (int i = 0; i < pis.Count; i++) {
- string paramType = GetReplacedString (
- MDocUpdater.GetDocParameterType (pis [i].ParameterType),
- typeParams, docTypeParams);
-
- // if magictypes, replace paramType to "classic value" ... so the comparison works
- string originalParamType = paramType;
- if (MDocUpdater.SwitchingToMagicTypes) {
- paramType = NativeTypeManager.ConvertFromNativeType (paramType);
- }
-
- string xmlMemberType = member.Parameters [i];
- if ((!paramType.Equals(xmlMemberType) && paramType.Equals(originalParamType)) ||
- (MDocUpdater.SwitchingToMagicTypes && !originalParamType.Equals(xmlMemberType) && !paramType.Equals(xmlMemberType) && !paramType.Equals(originalParamType))) {
-
- // did not match ... if we're dropping the namespace, and the paramType has the dropped
- // namespace, we should see if it matches when added
- bool stillDoesntMatch = true;
- if (MDocUpdater.HasDroppedNamespace(type) && paramType.StartsWith (MDocUpdater.droppedNamespace)) {
- string withDroppedNs = string.Format ("{0}.{1}", MDocUpdater.droppedNamespace, xmlMemberType);
-
- stillDoesntMatch = withDroppedNs != paramType;
- }
-
- if (stillDoesntMatch) {
- good = false;
- break;
- }
- }
-
- if (originalParamType != paramType)
- matchedMagicType = true;
- }
- if (!good) continue;
-
- if (MDocUpdater.SwitchingToMagicTypes && likelyCandidate == null && matchedMagicType) {
- // we matched this on a magic type conversion ... let's keep going to see if there's another one we should look at that matches more closely
- likelyCandidate = mi;
- continue;
- }
-
- return mi;
- }
-
- return likelyCandidate;
- }
-
- static string[] GetTypeParameters (string docName, IEnumerable<string> knownParameters)
- {
- if (docName [docName.Length-1] != '>')
- return null;
- StringList types = new StringList ();
- int endToken = docName.Length-2;
- int i = docName.Length-2;
- do {
- if (docName [i] == ',' || docName [i] == '<') {
- types.Add (docName.Substring (i + 1, endToken - i));
- endToken = i-1;
- }
- if (docName [i] == '<')
- break;
- } while (--i >= 0);
-
- types.Reverse ();
- var arrayTypes = types.ToArray ();
-
- if (knownParameters != null && knownParameters.Any () && arrayTypes.Length != knownParameters.Count ())
- return knownParameters.ToArray ();
- else
- return arrayTypes;
- }
-
- protected static IEnumerable<MemberReference> GetReflectionMembers (TypeDefinition type, string docName)
- {
- // In case of dropping the namespace, we have to remove the dropped NS
- // so that docName will match what's in the assembly/type
- if (MDocUpdater.HasDroppedNamespace (type) && docName.StartsWith(MDocUpdater.droppedNamespace + ".")) {
- int droppedNsLength = MDocUpdater.droppedNamespace.Length;
- docName = docName.Substring (droppedNsLength + 1, docName.Length - droppedNsLength - 1);
- }
-
- // need to worry about 4 forms of //@MemberName values:
- // 1. "Normal" (non-generic) member names: GetEnumerator
- // - Lookup as-is.
- // 2. Explicitly-implemented interface member names: System.Collections.IEnumerable.Current
- // - try as-is, and try type.member (due to "kludge" for property
- // support.
- // 3. "Normal" Generic member names: Sort<T> (CSC)
- // - need to remove generic parameters --> "Sort"
- // 4. Explicitly-implemented interface members for generic interfaces:
- // -- System.Collections.Generic.IEnumerable<T>.Current
- // - Try as-is, and try type.member, *keeping* the generic parameters.
- // --> System.Collections.Generic.IEnumerable<T>.Current, IEnumerable<T>.Current
- // 5. As of 2008-01-02, gmcs will do e.g. 'IFoo`1[A].Method' instead of
- // 'IFoo<A>.Method' for explicitly implemented methods; don't interpret
- // this as (1) or (2).
- if (docName.IndexOf ('<') == -1 && docName.IndexOf ('[') == -1) {
- // Cases 1 & 2
- foreach (MemberReference mi in type.GetMembers (docName))
- yield return mi;
- if (CountChars(docName, '.') > 0) {
-
- Func<MemberReference, bool> verifyInterface = (member) =>
- {
- var meth = member as MethodDefinition;
-
- if (meth == null && member is PropertyReference) {
- var propertyDefinition = ((PropertyReference)member).Resolve ();
- meth = propertyDefinition.GetMethod ?? propertyDefinition.SetMethod;
- }
- return meth != null && (member.Name.Equals (".ctor") || DocUtils.IsExplicitlyImplemented (meth));
- };
-
- int memberCount = 0;
-
- // might be a property; try only type.member instead of
- // namespace.type.member.
- var typeMember = DocUtils.GetTypeDotMember (docName);
- var memberName = DocUtils.GetMember (docName);
- foreach (MemberReference mi in
- type.GetMembers (typeMember).Where (verifyInterface)) {
- memberCount++;
- yield return mi;
- }
-
- // some VB libraries use just the member name
- foreach (MemberReference mi in
- type.GetMembers (memberName).Where (verifyInterface)) {
- memberCount++;
- yield return mi;
- }
-
- // some VB libraries use a `typemember` naming convention
- foreach (MemberReference mi in
- type.GetMembers (typeMember.Replace(".", "")).Where (verifyInterface)) {
- memberCount++;
- yield return mi;
- }
-
- // if we still haven't found the member, there are some VB libraries
- // that use a different interface name for implementation.
- if (memberCount == 0) {
- foreach (MemberReference mi in
- type
- .GetMembers ()
- .Where (m => m.Name.StartsWith ("I", StringComparison.InvariantCultureIgnoreCase) && m.Name.EndsWith (memberName, StringComparison.InvariantCultureIgnoreCase))
- .Where (verifyInterface))
- yield return mi;
- }
- }
- yield break;
- }
- // cases 3 & 4
- int numLt = 0;
- int numDot = 0;
- int startLt, startType, startMethod;
- startLt = startType = startMethod = -1;
- for (int i = 0; i < docName.Length; ++i) {
- switch (docName [i]) {
- case '<':
- if (numLt == 0) {
- startLt = i;
- }
- ++numLt;
- break;
- case '>':
- --numLt;
- if (numLt == 0 && (i + 1) < docName.Length)
- // there's another character in docName, so this <...> sequence is
- // probably part of a generic type -- case 4.
- startLt = -1;
- break;
- case '.':
- startType = startMethod;
- startMethod = i;
- ++numDot;
- break;
- }
- }
- string refName = startLt == -1 ? docName : docName.Substring (0, startLt);
- // case 3
- foreach (MemberReference mi in type.GetMembers (refName))
- yield return mi;
-
- // case 4
- foreach (MemberReference mi in type.GetMembers (refName.Substring (startType + 1)))
- yield return mi;
-
- // If we _still_ haven't found it, we've hit another generic naming issue:
- // post Mono 1.1.18, gmcs generates [[FQTN]] instead of <TypeName> for
- // explicitly-implemented METHOD names (not properties), e.g.
- // "System.Collections.Generic.IEnumerable`1[[Foo, test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null]].GetEnumerator"
- // instead of "System.Collections.Generic.IEnumerable<Foo>.GetEnumerator",
- // which the XML docs will contain.
- //
- // Alas, we can't derive the Mono name from docName, so we need to iterate
- // over all member names, convert them into CSC format, and compare... :-(
- if (numDot == 0)
- yield break;
- foreach (MemberReference mi in type.GetMembers ()) {
- if (MDocUpdater.GetMemberName (mi) == docName)
- yield return mi;
- }
- }
-
- static string GetReplacedString (string typeName, string[] from, string[] to)
- {
- if (from == null)
- return typeName;
- for (int i = 0; i < from.Length; ++i)
- typeName = typeName.Replace (from [i], to [i]);
- return typeName;
- }
-
- private static int CountChars (string s, char c)
- {
- int count = 0;
- for (int i = 0; i < s.Length; ++i) {
- if (s [i] == c)
- ++count;
- }
- return count;
- }
-}
-
-class EcmaDocumentationEnumerator : DocumentationEnumerator {
-
- XmlReader ecmadocs;
- MDocUpdater app;
-
- public EcmaDocumentationEnumerator (MDocUpdater app, XmlReader ecmaDocs)
- {
- this.app = app;
- this.ecmadocs = ecmaDocs;
- }
-
- public override IEnumerable<TypeDefinition> GetDocumentationTypes (AssemblyDefinition assembly, List<string> forTypes)
- {
- HashSet<string> seen = new HashSet<string> ();
- return GetDocumentationTypes (assembly, forTypes, seen)
- .Concat (base.GetDocumentationTypes (assembly, forTypes, seen));
- }
-
- new IEnumerable<TypeDefinition> GetDocumentationTypes (AssemblyDefinition assembly, List<string> forTypes, HashSet<string> seen)
- {
- int typeDepth = -1;
- while (ecmadocs.Read ()) {
- switch (ecmadocs.Name) {
- case "Type": {
- if (typeDepth == -1)
- typeDepth = ecmadocs.Depth;
- if (ecmadocs.NodeType != XmlNodeType.Element)
- continue;
- if (typeDepth != ecmadocs.Depth) // nested <TypeDefinition/> element?
- continue;
- string typename = ecmadocs.GetAttribute ("FullName");
- string typename2 = MDocUpdater.GetTypeFileName (typename);
- if (forTypes != null &&
- forTypes.BinarySearch (typename) < 0 &&
- typename != typename2 &&
- forTypes.BinarySearch (typename2) < 0)
- continue;
- TypeDefinition t;
- if ((t = assembly.GetType (typename)) == null &&
- (t = assembly.GetType (typename2)) == null)
- continue;
- seen.Add (typename);
- if (typename != typename2)
- seen.Add (typename2);
- Console.WriteLine (" Import: {0}", t.FullName);
- if (ecmadocs.Name != "Docs") {
- int depth = ecmadocs.Depth;
- while (ecmadocs.Read ()) {
- if (ecmadocs.Name == "Docs" && ecmadocs.Depth == depth + 1)
- break;
- }
- }
- if (!ecmadocs.IsStartElement ("Docs"))
- throw new InvalidOperationException ("Found " + ecmadocs.Name + "; expecting <Docs/>!");
- yield return t;
- break;
- }
- default:
- break;
- }
- }
- }
-
- public override IEnumerable<DocsNodeInfo> GetDocumentationMembers (XmlDocument basefile, TypeDefinition type)
- {
- return GetMembers (basefile, type)
- .Concat (base.GetDocumentationMembers (basefile, type));
- }
-
- private IEnumerable<DocsNodeInfo> GetMembers (XmlDocument basefile, TypeDefinition type)
- {
- while (ecmadocs.Name != "Members" && ecmadocs.Read ()) {
- // do nothing
- }
- if (ecmadocs.IsEmptyElement)
- yield break;
-
- int membersDepth = ecmadocs.Depth;
- bool go = true;
- while (go && ecmadocs.Read ()) {
- switch (ecmadocs.Name) {
- case "Member": {
- if (membersDepth != ecmadocs.Depth - 1 || ecmadocs.NodeType != XmlNodeType.Element)
- continue;
- DocumentationMember dm = new DocumentationMember (ecmadocs);
-
- string xp = MDocUpdater.GetXPathForMember (dm);
- XmlElement oldmember = (XmlElement) basefile.SelectSingleNode (xp);
- MemberReference m;
- if (oldmember == null) {
- m = GetMember (type, dm);
- if (m == null) {
- app.Warning ("Could not import ECMA docs for `{0}'s `{1}': Member not found.",
- type.FullName, dm.MemberSignatures ["C#"]);
- // SelectSingleNode (ecmaDocsMember, "MemberSignature[@Language=\"C#\"]/@Value").Value);
- continue;
- }
- // oldmember lookup may have failed due to type parameter renames.
- // Try again.
- oldmember = (XmlElement) basefile.SelectSingleNode (MDocUpdater.GetXPathForMember (m));
- if (oldmember == null) {
- XmlElement members = MDocUpdater.WriteElement (basefile.DocumentElement, "Members");
- oldmember = basefile.CreateElement ("Member");
- oldmember.SetAttribute ("MemberName", dm.MemberName);
- members.AppendChild (oldmember);
- foreach (string key in MDocUpdater.Sort (dm.MemberSignatures.Keys)) {
- XmlElement ms = basefile.CreateElement ("MemberSignature");
- ms.SetAttribute ("Language", key);
- ms.SetAttribute ("Value", (string) dm.MemberSignatures [key]);
- oldmember.AppendChild (ms);
- }
- oldmember.SetAttribute ("__monodocer-seen__", "true");
- Console.WriteLine ("Member Added: {0}", oldmember.SelectSingleNode("MemberSignature[@Language='C#']/@Value").InnerText);
- app.additions++;
- }
- }
- else {
- m = GetMember (type, new DocumentationMember (oldmember));
- if (m == null) {
- app.Warning ("Could not import ECMA docs for `{0}'s `{1}': Member not found.",
- type.FullName, dm.MemberSignatures ["C#"]);
- continue;
- }
- oldmember.SetAttribute ("__monodocer-seen__", "true");
- }
- DocsNodeInfo node = new DocsNodeInfo (oldmember, m);
- if (ecmadocs.Name != "Docs")
- throw new InvalidOperationException ("Found " + ecmadocs.Name + "; expected <Docs/>!");
- yield return node;
- break;
- }
- case "Members":
- if (membersDepth == ecmadocs.Depth && ecmadocs.NodeType == XmlNodeType.EndElement) {
- go = false;
- }
- break;
- }
- }
- }
-}
-
-abstract class DocumentationImporter {
-
- public abstract void ImportDocumentation (DocsNodeInfo info);
-}
-
-class MsxdocDocumentationImporter : DocumentationImporter {
-
- XmlDocument slashdocs;
-
- public MsxdocDocumentationImporter (string file)
- {
- try
- {
- char oppositeSlash = Path.DirectorySeparatorChar == '/' ? '\\' : '/';
- if (file.Contains (oppositeSlash))
- file = file.Replace (oppositeSlash, Path.DirectorySeparatorChar);
-
- var xml = File.ReadAllText (file);
-
- // Ensure Unix line endings
- xml = xml.Replace ("\r", "");
-
- slashdocs = new XmlDocument ();
-
- slashdocs.LoadXml (xml);
- }
- catch (IOException ex)
- {
- Console.WriteLine ($"Importer Error: {ex.Message}");
- }
- }
-
- public override void ImportDocumentation (DocsNodeInfo info)
- {
- XmlNode elem = GetDocs (info.Member ?? info.Type);
-
- if (elem == null)
- return;
-
- XmlElement e = info.Node;
-
- if (elem.SelectSingleNode("summary") != null)
- MDocUpdater.ClearElement(e, "summary");
- if (elem.SelectSingleNode("remarks") != null)
- MDocUpdater.ClearElement(e, "remarks");
- if (elem.SelectSingleNode ("value") != null || elem.SelectSingleNode ("returns") != null) {
- MDocUpdater.ClearElement(e, "value");
- MDocUpdater.ClearElement(e, "returns");
- }
-
- foreach (XmlNode child in elem.ChildNodes) {
- switch (child.Name) {
- case "param":
- case "typeparam": {
- XmlAttribute name = child.Attributes ["name"];
- if (name == null)
- break;
- XmlElement p2 = (XmlElement) e.SelectSingleNode (child.Name + "[@name='" + name.Value + "']");
- if (p2 != null)
- p2.InnerXml = child.InnerXml;
- break;
- }
- // Occasionally XML documentation will use <returns/> on
- // properties, so let's try to normalize things.
- case "value":
- case "returns": {
- XmlElement v = e.OwnerDocument.CreateElement (info.ReturnIsReturn ? "returns" : "value");
- v.InnerXml = child.InnerXml;
- e.AppendChild (v);
- break;
- }
- case "altmember":
- case "exception":
- case "permission": {
- XmlAttribute cref = child.Attributes ["cref"] ?? child.Attributes ["name"];
- if (cref == null)
- break;
- XmlElement a = (XmlElement) e.SelectSingleNode (child.Name + "[@cref='" + cref.Value + "']");
- if (a == null) {
- a = e.OwnerDocument.CreateElement (child.Name);
- a.SetAttribute ("cref", cref.Value);
- e.AppendChild (a);
- }
- a.InnerXml = child.InnerXml;
- break;
- }
- case "seealso": {
- XmlAttribute cref = child.Attributes ["cref"];
- if (cref == null)
- break;
- XmlElement a = (XmlElement) e.SelectSingleNode ("altmember[@cref='" + cref.Value + "']");
- if (a == null) {
- a = e.OwnerDocument.CreateElement ("altmember");
- a.SetAttribute ("cref", cref.Value);
- e.AppendChild (a);
- }
- break;
- }
- default: {
- bool add = true;
- if (child.NodeType == XmlNodeType.Element &&
- e.SelectNodes (child.Name).Cast<XmlElement>().Any (n => n.OuterXml == child.OuterXml))
- add = false;
- if (add)
- MDocUpdater.CopyNode (child, e);
- break;
- }
- }
- }
- }
-
- private XmlNode GetDocs (MemberReference member)
- {
- string slashdocsig = MDocUpdater.slashdocFormatter.GetDeclaration (member);
- if (slashdocsig != null && slashdocs != null)
- return slashdocs.SelectSingleNode ("doc/members/member[@name='" + slashdocsig + "']");
- return null;
- }
-}
-
-class EcmaDocumentationImporter : DocumentationImporter {
-
- XmlReader ecmadocs;
-
- public EcmaDocumentationImporter (XmlReader ecmaDocs)
- {
- this.ecmadocs = ecmaDocs;
- }
-
- public override void ImportDocumentation (DocsNodeInfo info)
- {
- if (!ecmadocs.IsStartElement ("Docs")) {
- return;
- }
-
- XmlElement e = info.Node;
-
- int depth = ecmadocs.Depth;
- ecmadocs.ReadStartElement ("Docs");
- while (ecmadocs.Read ()) {
- if (ecmadocs.Name == "Docs") {
- if (ecmadocs.Depth == depth && ecmadocs.NodeType == XmlNodeType.EndElement)
- break;
- else
- throw new InvalidOperationException ("Skipped past current <Docs/> element!");
- }
- if (!ecmadocs.IsStartElement ())
- continue;
- switch (ecmadocs.Name) {
- case "param":
- case "typeparam": {
- string name = ecmadocs.GetAttribute ("name");
- if (name == null)
- break;
- XmlNode doc = e.SelectSingleNode (
- ecmadocs.Name + "[@name='" + name + "']");
- string value = ecmadocs.ReadInnerXml ();
- if (doc != null)
- doc.InnerXml = value.Replace ("\r", "");
- break;
- }
- case "altmember":
- case "exception":
- case "permission":
- case "seealso": {
- string name = ecmadocs.Name;
- string cref = ecmadocs.GetAttribute ("cref");
- if (cref == null)
- break;
- XmlNode doc = e.SelectSingleNode (
- ecmadocs.Name + "[@cref='" + cref + "']");
- string value = ecmadocs.ReadInnerXml ().Replace ("\r", "");
- if (doc != null)
- doc.InnerXml = value;
- else {
- XmlElement n = e.OwnerDocument.CreateElement (name);
- n.SetAttribute ("cref", cref);
- n.InnerXml = value;
- e.AppendChild (n);
- }
- break;
- }
- default: {
- string name = ecmadocs.Name;
- string xpath = ecmadocs.Name;
- StringList attributes = new StringList (ecmadocs.AttributeCount);
- if (ecmadocs.MoveToFirstAttribute ()) {
- do {
- attributes.Add ("@" + ecmadocs.Name + "=\"" + ecmadocs.Value + "\"");
- } while (ecmadocs.MoveToNextAttribute ());
- ecmadocs.MoveToContent ();
- }
- if (attributes.Count > 0) {
- xpath += "[" + string.Join (" and ", attributes.ToArray ()) + "]";
- }
- XmlNode doc = e.SelectSingleNode (xpath);
- string value = ecmadocs.ReadInnerXml ().Replace ("\r", "");
- if (doc != null) {
- doc.InnerXml = value;
- }
- else {
- XmlElement n = e.OwnerDocument.CreateElement (name);
- n.InnerXml = value;
- foreach (string a in attributes) {
- int eq = a.IndexOf ('=');
- n.SetAttribute (a.Substring (1, eq-1), a.Substring (eq+2, a.Length-eq-3));
- }
- e.AppendChild (n);
- }
- break;
- }
- }
- }
- }
-}
-
-class DocumentationMember {
- public StringToStringMap MemberSignatures = new StringToStringMap ();
- public string ReturnType;
- public StringList Parameters;
- public StringList TypeParameters;
- public string MemberName;
- public string MemberType;
-
- /// <summary>Removes modreq and modopt from ReturnType, Parameters, and TypeParameters</summary>
- private void CleanTypes() {
- ReturnType = MemberFormatter.RemoveMod (ReturnType);
- MemberType = MemberFormatter.RemoveMod (MemberType);
-
- if (Parameters != null)
- {
- for (var i = 0; i < Parameters.Count; i++)
- Parameters[i] = MemberFormatter.RemoveMod (Parameters[i]);
- }
-
- if (TypeParameters != null)
- {
- for (var i = 0; i < TypeParameters.Count; i++)
- TypeParameters[i] = MemberFormatter.RemoveMod (TypeParameters[i]);
- }
- }
-
- public DocumentationMember (XmlReader reader)
- {
- MemberName = reader.GetAttribute ("MemberName");
- int depth = reader.Depth;
- bool go = true;
- StringList p = new StringList ();
- StringList tp = new StringList ();
- do {
- if (reader.NodeType != XmlNodeType.Element)
- continue;
-
- bool shouldUse = true;
- try {
- string apistyle = reader.GetAttribute ("apistyle");
- shouldUse = string.IsNullOrWhiteSpace(apistyle) || apistyle == "classic"; // only use this tag if it's an 'classic' style node
- }
- catch (Exception ex) {}
- switch (reader.Name) {
- case "MemberSignature":
- if (shouldUse) {
- MemberSignatures [reader.GetAttribute ("Language")] = reader.GetAttribute ("Value");
- }
- break;
- case "MemberType":
- MemberType = reader.ReadElementString ();
- break;
- case "ReturnType":
- if (reader.Depth == depth + 2 && shouldUse)
- ReturnType = reader.ReadElementString ();
- break;
- case "Parameter":
- if (reader.Depth == depth + 2 && shouldUse)
- p.Add (reader.GetAttribute ("Type"));
- break;
- case "TypeParameter":
- if (reader.Depth == depth + 2 && shouldUse)
- tp.Add (reader.GetAttribute ("Name"));
- break;
- case "Docs":
- if (reader.Depth == depth + 1)
- go = false;
- break;
- }
- } while (go && reader.Read () && reader.Depth >= depth);
- if (p.Count > 0) {
- Parameters = p;
- }
- if (tp.Count > 0) {
- TypeParameters = tp;
- } else {
- DiscernTypeParameters ();
- }
-
- CleanTypes ();
- }
-
- public DocumentationMember (XmlNode node)
- {
- MemberName = node.Attributes ["MemberName"].Value;
- foreach (XmlNode n in node.SelectNodes ("MemberSignature")) {
- XmlAttribute l = n.Attributes ["Language"];
- XmlAttribute v = n.Attributes ["Value"];
- XmlAttribute apistyle = n.Attributes ["apistyle"];
- bool shouldUse = apistyle == null || apistyle.Value == "classic";
- if (l != null && v != null && shouldUse)
- MemberSignatures [l.Value] = v.Value;
- }
- MemberType = node.SelectSingleNode ("MemberType").InnerText;
- XmlNode rt = node.SelectSingleNode ("ReturnValue/ReturnType[not(@apistyle) or @apistyle='classic']");
- if (rt != null)
- ReturnType = rt.InnerText;
- XmlNodeList p = node.SelectNodes ("Parameters/Parameter[not(@apistyle) or @apistyle='classic']");
- if (p.Count > 0) {
- Parameters = new StringList (p.Count);
- for (int i = 0; i < p.Count; ++i)
- Parameters.Add (p [i].Attributes ["Type"].Value);
- }
- XmlNodeList tp = node.SelectNodes ("TypeParameters/TypeParameter[not(@apistyle) or @apistyle='classic']");
- if (tp.Count > 0) {
- TypeParameters = new StringList (tp.Count);
- for (int i = 0; i < tp.Count; ++i)
- TypeParameters.Add (tp [i].Attributes ["Name"].Value);
- }
- else {
- DiscernTypeParameters ();
- }
-
- CleanTypes ();
- }
-
- void DiscernTypeParameters ()
- {
- // see if we can discern the param list from the name
- if (MemberName.Contains ("<") && MemberName.EndsWith (">")) {
- var starti = MemberName.IndexOf ("<") + 1;
- var endi = MemberName.LastIndexOf (">");
- var paramlist = MemberName.Substring (starti, endi - starti);
- var tparams = paramlist.Split (new char[] {','}, StringSplitOptions.RemoveEmptyEntries);
- TypeParameters = new StringList (tparams);
- }
- }
-}
-
-public class DynamicParserContext {
- public ReadOnlyCollection<bool> TransformFlags;
- public int TransformIndex;
-
- public DynamicParserContext (ICustomAttributeProvider provider)
- {
- CustomAttribute da;
- if (provider.HasCustomAttributes &&
- (da = (provider.CustomAttributes.Cast<CustomAttribute>()
- .SingleOrDefault (ca => ca.GetDeclaringType() == "System.Runtime.CompilerServices.DynamicAttribute"))) != null) {
- CustomAttributeArgument[] values = da.ConstructorArguments.Count == 0
- ? new CustomAttributeArgument [0]
- : (CustomAttributeArgument[]) da.ConstructorArguments [0].Value;
-
- TransformFlags = new ReadOnlyCollection<bool> (values.Select (t => (bool) t.Value).ToArray());
- }
- }
-}
-
-public enum MemberFormatterState {
- None,
- WithinGenericTypeParameters,
-}
-
-public abstract class MemberFormatter {
-
- public virtual string Language {
- get {return "";}
- }
-
- public string GetName (MemberReference member)
- {
- return GetName (member, null);
- }
-
- public virtual string GetName (MemberReference member, DynamicParserContext context)
- {
- TypeReference type = member as TypeReference;
- if (type != null)
- return GetTypeName (type, context);
- MethodReference method = member as MethodReference;
- if (method != null && method.Name == ".ctor") // method.IsConstructor
- return GetConstructorName (method);
- if (method != null)
- return GetMethodName (method);
- PropertyReference prop = member as PropertyReference;
- if (prop != null)
- return GetPropertyName (prop);
- FieldReference field = member as FieldReference;
- if (field != null)
- return GetFieldName (field);
- EventReference e = member as EventReference;
- if (e != null)
- return GetEventName (e);
- throw new NotSupportedException ("Can't handle: " +
- (member == null ? "null" : member.GetType().ToString()));
- }
-
- protected virtual string GetTypeName (TypeReference type)
- {
- return GetTypeName (type, null);
- }
-
- protected virtual string GetTypeName (TypeReference type, DynamicParserContext context)
- {
- if (type == null)
- throw new ArgumentNullException (nameof (type));
-
- var typeName = _AppendTypeName (new StringBuilder (type.Name.Length), type, context).ToString ();
-
- typeName = RemoveMod (typeName);
-
- return typeName;
- }
-
- public static string RemoveMod (string typeName)
- {
- if (string.IsNullOrWhiteSpace (typeName)) return typeName;
-
- // For custom modifiers (modopt/modreq), we are just excising them
- // via string manipulation for simplicity; since these cannot be
- // expressed in C#. If finer control is needed in the future, you can
- // use IModifierType, PointerType, ByReferenceType, etc.
-
- int modIndex = Math.Max (typeName.LastIndexOf ("modopt(", StringComparison.Ordinal), typeName.LastIndexOf ("modreq(", StringComparison.Ordinal));
- if (modIndex > 0)
- {
- var tname = typeName.Substring (0, modIndex - 1);
- var parenIndex = typeName.LastIndexOf (')');
- if (parenIndex == typeName.Length - 2)
- { // see if there's metadata like a pointer
- tname += typeName.Last ();
- }
- typeName = tname;
- }
-
- modIndex = Math.Max (typeName.LastIndexOf ("modopt(", StringComparison.Ordinal), typeName.LastIndexOf ("modreq(", StringComparison.Ordinal));
- if (modIndex >= 0)
- return RemoveMod (typeName);
- else
- return typeName;
- }
-
- protected virtual char[] ArrayDelimeters {
- get {return new char[]{'[', ']'};}
- }
-
- protected virtual MemberFormatterState MemberFormatterState { get; set; }
-
- protected StringBuilder _AppendTypeName (StringBuilder buf, TypeReference type, DynamicParserContext context)
- {
- if (type is ArrayType) {
- TypeSpecification spec = type as TypeSpecification;
- _AppendTypeName (buf, spec != null ? spec.ElementType : type.GetElementType (), context);
- return AppendArrayModifiers (buf, (ArrayType) type);
- }
- if (type is ByReferenceType) {
- return AppendRefTypeName (buf, type, context);
- }
- if (type is PointerType) {
- return AppendPointerTypeName (buf, type, context);
- }
- if (type is GenericParameter) {
- return AppendTypeName (buf, type, context);
- }
- AppendNamespace (buf, type);
- GenericInstanceType genInst = type as GenericInstanceType;
- if (type.GenericParameters.Count == 0 &&
- (genInst == null ? true : genInst.GenericArguments.Count == 0)) {
- return AppendFullTypeName (buf, type, context);
- }
- return AppendGenericType (buf, type, context);
- }
-
- protected virtual StringBuilder AppendNamespace (StringBuilder buf, TypeReference type)
- {
- string ns = DocUtils.GetNamespace (type);
- if (ns != null && ns.Length > 0)
- buf.Append (ns).Append ('.');
- return buf;
- }
-
- protected virtual StringBuilder AppendFullTypeName (StringBuilder buf, TypeReference type, DynamicParserContext context)
- {
- if (type.DeclaringType != null)
- AppendFullTypeName (buf, type.DeclaringType, context).Append (NestedTypeSeparator);
- return AppendTypeName (buf, type, context);
- }
-
- protected virtual StringBuilder AppendTypeName (StringBuilder buf, TypeReference type, DynamicParserContext context)
- {
- if (context != null)
- context.TransformIndex++;
- return AppendTypeName (buf, type.Name);
- }
-
- protected virtual StringBuilder AppendTypeName (StringBuilder buf, string typename)
- {
- int n = typename.IndexOf ("`");
- if (n >= 0)
- return buf.Append (typename.Substring (0, n));
- return buf.Append (typename);
- }
-
- protected virtual StringBuilder AppendArrayModifiers (StringBuilder buf, ArrayType array)
- {
- buf.Append (ArrayDelimeters [0]);
- int rank = array.Rank;
- if (rank > 1)
- buf.Append (new string (',', rank-1));
- return buf.Append (ArrayDelimeters [1]);
- }
-
- protected virtual string RefTypeModifier {
- get {return "@";}
- }
-
- protected virtual StringBuilder AppendRefTypeName (StringBuilder buf, TypeReference type, DynamicParserContext context)
- {
- TypeSpecification spec = type as TypeSpecification;
- return _AppendTypeName (buf, spec != null ? spec.ElementType : type.GetElementType (), context)
- .Append (RefTypeModifier);
- }
-
- protected virtual string PointerModifier {
- get {return "*";}
- }
-
- protected virtual StringBuilder AppendPointerTypeName (StringBuilder buf, TypeReference type, DynamicParserContext context)
- {
- TypeSpecification spec = type as TypeSpecification;
- return _AppendTypeName (buf, spec != null ? spec.ElementType : type.GetElementType (), context)
- .Append (PointerModifier);
- }
-
- protected virtual char[] GenericTypeContainer {
- get {return new char[]{'<', '>'};}
- }
-
- protected virtual char NestedTypeSeparator {
- get {return '.';}
- }
-
- protected virtual StringBuilder AppendGenericType (StringBuilder buf, TypeReference type, DynamicParserContext context)
- {
- List<TypeReference> decls = DocUtils.GetDeclaringTypes (
- type is GenericInstanceType ? type.GetElementType () : type);
- List<TypeReference> genArgs = GetGenericArguments (type);
- int argIdx = 0;
- int prev = 0;
- bool insertNested = false;
- foreach (var decl in decls) {
- TypeReference declDef = decl.Resolve () ?? decl;
- if (insertNested) {
- buf.Append (NestedTypeSeparator);
- }
- insertNested = true;
- AppendTypeName (buf, declDef, context);
- int ac = DocUtils.GetGenericArgumentCount (declDef);
- int c = ac - prev;
- prev = ac;
- if (c > 0) {
- buf.Append (GenericTypeContainer [0]);
- var origState = MemberFormatterState;
- MemberFormatterState = MemberFormatterState.WithinGenericTypeParameters;
- _AppendTypeName (buf, genArgs [argIdx++], context);
- for (int i = 1; i < c; ++i) {
- _AppendTypeName (buf.Append (","), genArgs [argIdx++], context);
- }
- MemberFormatterState = origState;
- buf.Append (GenericTypeContainer [1]);
- }
- }
- return buf;
- }
-
- protected List<TypeReference> GetGenericArguments (TypeReference type)
- {
- var args = new List<TypeReference> ();
- GenericInstanceType inst = type as GenericInstanceType;
- if (inst != null)
- args.AddRange (inst.GenericArguments.Cast<TypeReference> ());
- else
- args.AddRange (type.GenericParameters.Cast<TypeReference> ());
- return args;
- }
-
- protected virtual StringBuilder AppendGenericTypeConstraints (StringBuilder buf, TypeReference type)
- {
- return buf;
- }
-
- protected virtual string GetConstructorName (MethodReference constructor)
- {
- return constructor.Name;
- }
-
- protected virtual string GetMethodName (MethodReference method)
- {
- return method.Name;
- }
-
- protected virtual string GetPropertyName (PropertyReference property)
- {
- return property.Name;
- }
-
- protected virtual string GetFieldName (FieldReference field)
- {
- return field.Name;
- }
-
- protected virtual string GetEventName (EventReference e)
- {
- return e.Name;
- }
-
- public virtual string GetDeclaration (TypeReference tref)
- {
- var typeSpec = tref as TypeSpecification;
- if (typeSpec != null && typeSpec.Resolve () == null && typeSpec.IsArray && typeSpec.ContainsGenericParameter) {
- //HACK: there's really no good reference for a generic parameter array, so we're going to use object
- return "T:System.Array";
- }
- TypeDefinition def = tref.Resolve ();
- if (def != null)
- return GetTypeDeclaration (def);
- else
- return GetTypeName (tref);
- }
-
- public virtual string GetDeclaration (MemberReference mreference)
- {
- return GetDeclaration (mreference.Resolve ());
- }
-
- string GetDeclaration (IMemberDefinition member)
- {
- if (member == null)
- throw new ArgumentNullException ("member");
- TypeDefinition type = member as TypeDefinition;
- if (type != null)
- return GetTypeDeclaration (type);
- MethodDefinition method = member as MethodDefinition;
- if (method != null && method.IsConstructor)
- return GetConstructorDeclaration (method);
- if (method != null)
- return GetMethodDeclaration (method);
- PropertyDefinition prop = member as PropertyDefinition;
- if (prop != null)
- return GetPropertyDeclaration (prop);
- FieldDefinition field = member as FieldDefinition;
- if (field != null)
- return GetFieldDeclaration (field);
- EventDefinition e = member as EventDefinition;
- if (e != null)
- return GetEventDeclaration (e);
- throw new NotSupportedException ("Can't handle: " + member.GetType().ToString());
- }
-
- protected virtual string GetTypeDeclaration (TypeDefinition type)
- {
- if (type == null)
- throw new ArgumentNullException ("type");
- StringBuilder buf = new StringBuilder (type.Name.Length);
- _AppendTypeName (buf, type, null);
- AppendGenericTypeConstraints (buf, type);
- return buf.ToString ();
- }
-
- protected virtual string GetConstructorDeclaration (MethodDefinition constructor)
- {
- return GetConstructorName (constructor);
- }
-
- protected virtual string GetMethodDeclaration (MethodDefinition method)
- {
- if (method.HasCustomAttributes && method.CustomAttributes.Cast<CustomAttribute>().Any(
- ca => ca.GetDeclaringType() == "System.Diagnostics.Contracts.ContractInvariantMethodAttribute"))
- return null;
-
- // Special signature for destructors.
- if (method.Name == "Finalize" && method.Parameters.Count == 0)
- return GetFinalizerName (method);
-
- StringBuilder buf = new StringBuilder ();
-
- AppendVisibility (buf, method);
- if (buf.Length == 0 &&
- !(DocUtils.IsExplicitlyImplemented (method) && !method.IsSpecialName))
- return null;
-
- AppendModifiers (buf, method);
-
- if (buf.Length != 0)
- buf.Append (" ");
-
- buf.Append (GetTypeName (method.ReturnType, new DynamicParserContext (method.MethodReturnType))).Append (" ");
-
- AppendMethodName (buf, method);
- AppendGenericMethod (buf, method).Append (" ");
- AppendParameters (buf, method, method.Parameters);
- AppendGenericMethodConstraints (buf, method);
- return buf.ToString ();
- }
-
- protected virtual StringBuilder AppendMethodName (StringBuilder buf, MethodDefinition method)
- {
- return buf.Append (method.Name);
- }
-
- protected virtual string GetFinalizerName (MethodDefinition method)
- {
- return "Finalize";
- }
-
- protected virtual StringBuilder AppendVisibility (StringBuilder buf, MethodDefinition method)
- {
- return buf;
- }
-
- protected virtual StringBuilder AppendModifiers (StringBuilder buf, MethodDefinition method)
- {
- return buf;
- }
-
- protected virtual StringBuilder AppendGenericMethod (StringBuilder buf, MethodDefinition method)
- {
- return buf;
- }
-
- protected virtual StringBuilder AppendParameters (StringBuilder buf, MethodDefinition method, IList<ParameterDefinition> parameters)
- {
- return buf;
- }
-
- protected virtual StringBuilder AppendGenericMethodConstraints (StringBuilder buf, MethodDefinition method)
- {
- return buf;
- }
-
- protected virtual string GetPropertyDeclaration (PropertyDefinition property)
- {
- return GetPropertyName (property);
- }
-
- protected virtual string GetFieldDeclaration (FieldDefinition field)
- {
- return GetFieldName (field);
- }
-
- protected virtual string GetEventDeclaration (EventDefinition e)
- {
- return GetEventName (e);
- }
-}
-
-class DocIdFormatter : MemberFormatter
-{
- public override string Language
- {
- get { return "DocId"; }
- }
-
- public override string GetDeclaration (TypeReference tref)
- {
- return DocCommentId.GetDocCommentId (tref.Resolve ());
- }
- public override string GetDeclaration (MemberReference mreference)
- {
- return DocCommentId.GetDocCommentId (mreference.Resolve ());
- }
-}
-
-public class ILFullMemberFormatter : MemberFormatter {
-
- public override string Language {
- get {return "ILAsm";}
- }
-
- protected override char NestedTypeSeparator {
- get {
- return '/';
- }
- }
-
- protected override StringBuilder AppendNamespace (StringBuilder buf, TypeReference type)
- {
- if (GetBuiltinType (type.FullName) != null)
- return buf;
- string ns = DocUtils.GetNamespace (type);
- if (ns != null && ns.Length > 0) {
- if (type.IsValueType)
- buf.Append ("valuetype ");
- else
- buf.Append ("class ");
- buf.Append (ns).Append ('.');
- }
- return buf;
- }
-
- protected static string GetBuiltinType (string t)
- {
- switch (t) {
- case "System.Byte": return "unsigned int8";
- case "System.SByte": return "int8";
- case "System.Int16": return "int16";
- case "System.Int32": return "int32";
- case "System.Int64": return "int64";
- case "System.IntPtr": return "native int";
-
- case "System.UInt16": return "unsigned int16";
- case "System.UInt32": return "unsigned int32";
- case "System.UInt64": return "unsigned int64";
- case "System.UIntPtr": return "native unsigned int";
-
- case "System.Single": return "float32";
- case "System.Double": return "float64";
- case "System.Boolean": return "bool";
- case "System.Char": return "char";
- case "System.Void": return "void";
- case "System.String": return "string";
- case "System.Object": return "object";
- }
- return null;
- }
-
- protected override StringBuilder AppendTypeName (StringBuilder buf, string typename)
- {
- return buf.Append (typename);
- }
-
- protected override StringBuilder AppendTypeName (StringBuilder buf, TypeReference type, DynamicParserContext context)
- {
- if (type is GenericParameter) {
- AppendGenericParameterConstraints (buf, (GenericParameter) type).Append (type.Name);
- return buf;
- }
-
- string s = GetBuiltinType (type.FullName);
- if (s != null) {
- return buf.Append (s);
- }
- return base.AppendTypeName (buf, type, context);
- }
-
- private StringBuilder AppendGenericParameterConstraints (StringBuilder buf, GenericParameter type)
- {
- if (MemberFormatterState != MemberFormatterState.WithinGenericTypeParameters) {
- return buf.Append (type.Owner is TypeReference ? "!" : "!!");
- }
- GenericParameterAttributes attrs = type.Attributes;
- if ((attrs & GenericParameterAttributes.ReferenceTypeConstraint) != 0)
- buf.Append ("class ");
- if ((attrs & GenericParameterAttributes.NotNullableValueTypeConstraint) != 0)
- buf.Append ("struct ");
- if ((attrs & GenericParameterAttributes.DefaultConstructorConstraint) != 0)
- buf.Append (".ctor ");
- IList<TypeReference> constraints = type.Constraints;
- MemberFormatterState = 0;
- if (constraints.Count > 0) {
- var full = new ILFullMemberFormatter ();
- buf.Append ("(").Append (full.GetName (constraints [0]));
- for (int i = 1; i < constraints.Count; ++i) {
- buf.Append (", ").Append (full.GetName (constraints [i]));
- }
- buf.Append (") ");
- }
- MemberFormatterState = MemberFormatterState.WithinGenericTypeParameters;
-
- if ((attrs & GenericParameterAttributes.Covariant) != 0)
- buf.Append ("+ ");
- if ((attrs & GenericParameterAttributes.Contravariant) != 0)
- buf.Append ("- ");
- return buf;
- }
-
- protected override string GetTypeDeclaration (TypeDefinition type)
- {
- string visibility = GetTypeVisibility (type.Attributes);
- if (visibility == null)
- return null;
-
- StringBuilder buf = new StringBuilder ();
-
- buf.Append (".class ");
- if (type.IsNested)
- buf.Append ("nested ");
- buf.Append (visibility).Append (" ");
- if (type.IsInterface)
- buf.Append ("interface ");
- if (type.IsSequentialLayout)
- buf.Append ("sequential ");
- if (type.IsAutoLayout)
- buf.Append ("auto ");
- if (type.IsAnsiClass)
- buf.Append ("ansi ");
- if (type.IsAbstract)
- buf.Append ("abstract ");
- if (type.IsSerializable)
- buf.Append ("serializable ");
- if (type.IsSealed)
- buf.Append ("sealed ");
- if (type.IsBeforeFieldInit)
- buf.Append ("beforefieldinit ");
- var state = MemberFormatterState;
- MemberFormatterState = MemberFormatterState.WithinGenericTypeParameters;
- buf.Append (GetName (type));
- MemberFormatterState = state;
- var full = new ILFullMemberFormatter ();
- if (type.BaseType != null) {
- buf.Append (" extends ");
- if (type.BaseType.FullName == "System.Object")
- buf.Append ("System.Object");
- else
- buf.Append (full.GetName (type.BaseType).Substring ("class ".Length));
- }
- bool first = true;
- foreach (var name in type.Interfaces.Where (i => MDocUpdater.IsPublic (i.InterfaceType.Resolve ()))
- .Select (i => full.GetName (i.InterfaceType))
- .OrderBy (n => n)) {
- if (first) {
- buf.Append (" implements ");
- first = false;
- }
- else {
- buf.Append (", ");
- }
- buf.Append (name);
- }
-
- return buf.ToString ();
- }
-
- protected override StringBuilder AppendGenericType (StringBuilder buf, TypeReference type, DynamicParserContext context)
- {
- List<TypeReference> decls = DocUtils.GetDeclaringTypes (
- type is GenericInstanceType ? type.GetElementType () : type);
- bool first = true;
- foreach (var decl in decls) {
- TypeReference declDef = decl.Resolve () ?? decl;
- if (!first) {
- buf.Append (NestedTypeSeparator);
- }
- first = false;
- AppendTypeName (buf, declDef, context);
- }
- buf.Append ('<');
- first = true;
- foreach (TypeReference arg in GetGenericArguments (type)) {
- if (!first)
- buf.Append (", ");
- first = false;
- _AppendTypeName (buf, arg, context);
- }
- buf.Append ('>');
- return buf;
- }
-
- static string GetTypeVisibility (TypeAttributes ta)
- {
- switch (ta & TypeAttributes.VisibilityMask) {
- case TypeAttributes.Public:
- case TypeAttributes.NestedPublic:
- return "public";
-
- case TypeAttributes.NestedFamily:
- case TypeAttributes.NestedFamORAssem:
- return "protected";
-
- default:
- return null;
- }
- }
-
- protected override string GetConstructorDeclaration (MethodDefinition constructor)
- {
- return GetMethodDeclaration (constructor);
- }
-
- protected override string GetMethodDeclaration (MethodDefinition method)
- {
- if (method.IsPrivate && !DocUtils.IsExplicitlyImplemented (method))
- return null;
-
- var buf = new StringBuilder ();
- buf.Append (".method ");
- AppendVisibility (buf, method);
- if (method.IsStatic)
- buf.Append ("static ");
- if (method.IsHideBySig)
- buf.Append ("hidebysig ");
- if (method.IsPInvokeImpl) {
- var info = method.PInvokeInfo;
- buf.Append ("pinvokeimpl (\"")
- .Append (info.Module.Name)
- .Append ("\" as \"")
- .Append (info.EntryPoint)
- .Append ("\"");
- if (info.IsCharSetAuto)
- buf.Append (" auto");
- if (info.IsCharSetUnicode)
- buf.Append (" unicode");
- if (info.IsCharSetAnsi)
- buf.Append (" ansi");
- if (info.IsCallConvCdecl)
- buf.Append (" cdecl");
- if (info.IsCallConvStdCall)
- buf.Append (" stdcall");
- if (info.IsCallConvWinapi)
- buf.Append (" winapi");
- if (info.IsCallConvThiscall)
- buf.Append (" thiscall");
- if (info.SupportsLastError)
- buf.Append (" lasterr");
- buf.Append (")");
- }
- if (method.IsSpecialName)
- buf.Append ("specialname ");
- if (method.IsRuntimeSpecialName)
- buf.Append ("rtspecialname ");
- if (method.IsNewSlot)
- buf.Append ("newslot ");
- if (method.IsVirtual)
- buf.Append ("virtual ");
- if (!method.IsStatic)
- buf.Append ("instance ");
- _AppendTypeName (buf, method.ReturnType, new DynamicParserContext (method.MethodReturnType));
- buf.Append (' ')
- .Append (method.Name);
- if (method.IsGenericMethod ()) {
- var state = MemberFormatterState;
- MemberFormatterState = MemberFormatterState.WithinGenericTypeParameters;
- IList<GenericParameter> args = method.GenericParameters;
- if (args.Count > 0) {
- buf.Append ("<");
- _AppendTypeName (buf, args [0], null);
- for (int i = 1; i < args.Count; ++i)
- _AppendTypeName (buf.Append (", "), args [i], null);
- buf.Append (">");
- }
- MemberFormatterState = state;
- }
-
- buf.Append ('(');
- bool first = true;
- for (int i = 0; i < method.Parameters.Count; ++i) {
- var param = method.Parameters[i];
- if (!first)
- buf.Append (", ");
- first = false;
-
- if (param.IsOut) buf.Append ("[out] ");
- else if (param.IsIn) buf.Append ("[in]");
-
- _AppendTypeName (buf, param.ParameterType, new DynamicParserContext (param));
- if (param.ParameterType.IsByReference) buf.Append ("&");
- buf.Append (' ');
- buf.Append (param.Name);
- }
- buf.Append (')');
- if (method.IsIL)
- buf.Append (" cil");
- if (method.IsRuntime)
- buf.Append (" runtime");
- if (method.IsManaged)
- buf.Append (" managed");
-
- return buf.ToString ();
- }
-
- protected override StringBuilder AppendMethodName (StringBuilder buf, MethodDefinition method)
- {
- if (DocUtils.IsExplicitlyImplemented (method)) {
- TypeReference iface;
- MethodReference ifaceMethod;
- DocUtils.GetInfoForExplicitlyImplementedMethod (method, out iface, out ifaceMethod);
- return buf.Append (new CSharpMemberFormatter ().GetName (iface))
- .Append ('.')
- .Append (ifaceMethod.Name);
- }
- return base.AppendMethodName (buf, method);
- }
-
- protected override string RefTypeModifier {
- get {return "";}
- }
-
- protected override StringBuilder AppendVisibility (StringBuilder buf, MethodDefinition method)
- {
- if (method.IsPublic)
- return buf.Append ("public ");
- if (method.IsFamilyAndAssembly)
- return buf.Append ("familyandassembly");
- if (method.IsFamilyOrAssembly)
- return buf.Append ("familyorassembly");
- if (method.IsFamily)
- return buf.Append ("family");
- return buf;
- }
-
- protected override StringBuilder AppendModifiers (StringBuilder buf, MethodDefinition method)
- {
- string modifiers = String.Empty;
- if (method.IsStatic) modifiers += " static";
- if (method.IsVirtual && !method.IsAbstract) {
- if ((method.Attributes & MethodAttributes.NewSlot) != 0) modifiers += " virtual";
- else modifiers += " override";
- }
- TypeDefinition declType = (TypeDefinition) method.DeclaringType;
- if (method.IsAbstract && !declType.IsInterface) modifiers += " abstract";
- if (method.IsFinal) modifiers += " sealed";
- if (modifiers == " virtual sealed") modifiers = "";
-
- return buf.Append (modifiers);
- }
-
- protected override StringBuilder AppendGenericMethod (StringBuilder buf, MethodDefinition method)
- {
- if (method.IsGenericMethod ()) {
- IList<GenericParameter> args = method.GenericParameters;
- if (args.Count > 0) {
- buf.Append ("<");
- buf.Append (args [0].Name);
- for (int i = 1; i < args.Count; ++i)
- buf.Append (",").Append (args [i].Name);
- buf.Append (">");
- }
- }
- return buf;
- }
-
- protected override StringBuilder AppendParameters (StringBuilder buf, MethodDefinition method, IList<ParameterDefinition> parameters)
- {
- return AppendParameters (buf, method, parameters, '(', ')');
- }
-
- private StringBuilder AppendParameters (StringBuilder buf, MethodDefinition method, IList<ParameterDefinition> parameters, char begin, char end)
- {
- buf.Append (begin);
-
- if (parameters.Count > 0) {
- if (DocUtils.IsExtensionMethod (method))
- buf.Append ("this ");
- AppendParameter (buf, parameters [0]);
- for (int i = 1; i < parameters.Count; ++i) {
- buf.Append (", ");
- AppendParameter (buf, parameters [i]);
- }
- }
-
- return buf.Append (end);
- }
-
- private StringBuilder AppendParameter (StringBuilder buf, ParameterDefinition parameter)
- {
- if (parameter.ParameterType is ByReferenceType) {
- if (parameter.IsOut)
- buf.Append ("out ");
- else
- buf.Append ("ref ");
- }
- buf.Append (GetName (parameter.ParameterType)).Append (" ");
- return buf.Append (parameter.Name);
- }
-
- protected override string GetPropertyDeclaration (PropertyDefinition property)
- {
- MethodDefinition gm = null, sm = null;
-
- string get_visible = null;
- if ((gm = property.GetMethod) != null &&
- (DocUtils.IsExplicitlyImplemented (gm) ||
- (!gm.IsPrivate && !gm.IsAssembly && !gm.IsFamilyAndAssembly)))
- get_visible = AppendVisibility (new StringBuilder (), gm).ToString ();
- string set_visible = null;
- if ((sm = property.SetMethod) != null &&
- (DocUtils.IsExplicitlyImplemented (sm) ||
- (!sm.IsPrivate && !sm.IsAssembly && !sm.IsFamilyAndAssembly)))
- set_visible = AppendVisibility (new StringBuilder (), sm).ToString ();
-
- if ((set_visible == null) && (get_visible == null))
- return null;
-
- StringBuilder buf = new StringBuilder ()
- .Append (".property ");
- if (!(gm ?? sm).IsStatic)
- buf.Append ("instance ");
- _AppendTypeName (buf, property.PropertyType, new DynamicParserContext (property));
- buf.Append (' ').Append (property.Name);
- if (!property.HasParameters || property.Parameters.Count == 0)
- return buf.ToString ();
-
- buf.Append ('(');
- bool first = true;
- foreach (ParameterDefinition p in property.Parameters) {
- if (!first)
- buf.Append (", ");
- first = false;
- _AppendTypeName (buf, p.ParameterType, new DynamicParserContext (p));
- }
- buf.Append (')');
-
- return buf.ToString ();
- }
-
- protected override string GetFieldDeclaration (FieldDefinition field)
- {
- TypeDefinition declType = (TypeDefinition) field.DeclaringType;
- if (declType.IsEnum && field.Name == "value__")
- return null; // This member of enums aren't documented.
-
- StringBuilder buf = new StringBuilder ();
- AppendFieldVisibility (buf, field);
- if (buf.Length == 0)
- return null;
-
- buf.Insert (0, ".field ");
-
- if (field.IsStatic)
- buf.Append ("static ");
- if (field.IsInitOnly)
- buf.Append ("initonly ");
- if (field.IsLiteral)
- buf.Append ("literal ");
- _AppendTypeName (buf, field.FieldType, new DynamicParserContext (field));
- buf.Append (' ').Append (field.Name);
- AppendFieldValue (buf, field);
-
- return buf.ToString ();
- }
-
- static StringBuilder AppendFieldVisibility (StringBuilder buf, FieldDefinition field)
- {
- if (field.IsPublic)
- return buf.Append ("public ");
- if (field.IsFamilyAndAssembly)
- return buf.Append ("familyandassembly ");
- if (field.IsFamilyOrAssembly)
- return buf.Append ("familyorassembly ");
- if (field.IsFamily)
- return buf.Append ("family ");
- return buf;
- }
-
- static StringBuilder AppendFieldValue (StringBuilder buf, FieldDefinition field)
- {
- // enums have a value__ field, which we ignore
- if (field.DeclaringType.IsGenericType ())
- return buf;
- if (field.HasConstant && field.IsLiteral) {
- object val = null;
- try {
- val = field.Constant;
- } catch {
- return buf;
- }
- if (val == null)
- buf.Append (" = ").Append ("null");
- else if (val is Enum)
- buf.Append (" = ")
- .Append (GetBuiltinType (field.DeclaringType.GetUnderlyingType ().FullName))
- .Append ('(')
- .Append (val.ToString ())
- .Append (')');
- else if (val is IFormattable) {
- string value = ((IFormattable)val).ToString(null, CultureInfo.InvariantCulture);
- buf.Append (" = ");
- if (val is string)
- buf.Append ("\"" + value + "\"");
- else
- buf.Append (GetBuiltinType (field.DeclaringType.GetUnderlyingType ().FullName))
- .Append ('(')
- .Append (value)
- .Append (')');
- }
- }
- return buf;
- }
-
- protected override string GetEventDeclaration (EventDefinition e)
- {
- StringBuilder buf = new StringBuilder ();
- if (AppendVisibility (buf, e.AddMethod).Length == 0) {
- return null;
- }
-
- buf.Length = 0;
- buf.Append (".event ")
- .Append (GetName (e.EventType))
- .Append (' ')
- .Append (e.Name);
-
- return buf.ToString ();
- }
-}
-
-public class ILMemberFormatter : ILFullMemberFormatter {
- protected override StringBuilder AppendNamespace (StringBuilder buf, TypeReference type)
- {
- return buf;
- }
-}
-
- class ILNativeTypeMemberFormatter : ILFullMemberFormatter {
- protected static string _GetBuiltinType (string t)
- {
- //string moddedType = base.GetBuiltinType (t);
- return null;
- //return moddedType;
- }
- }
-
- class CSharpNativeTypeMemberFormatter : CSharpFullMemberFormatter {
- protected override string GetCSharpType (string t) {
- string moddedType = base.GetCSharpType (t);
-
- switch (moddedType) {
- case "int": return "nint";
- case "uint":
- return "nuint";
- case "float":
- return "nfloat";
- case "System.Drawing.SizeF":
- return "CoreGraphics.CGSize";
- case "System.Drawing.PointF":
- return "CoreGraphics.CGPoint";
- case "System.Drawing.RectangleF":
- return "CoreGraphics.CGPoint";
- }
- return null;
- }
- }
-
-public class CSharpFullMemberFormatter : MemberFormatter {
-
- public override string Language {
- get {return "C#";}
- }
-
- protected override StringBuilder AppendNamespace (StringBuilder buf, TypeReference type)
- {
-
- string ns = DocUtils.GetNamespace (type);
- if (GetCSharpType (type.FullName) == null && ns != null && ns.Length > 0 && ns != "System")
- buf.Append (ns).Append ('.');
- return buf;
- }
-
- protected virtual string GetCSharpType (string t)
- {
- // make sure there are no modifiers in the type string (add them back before returning)
- string typeToCompare = t;
- string[] splitType = null;
- if (t.Contains (' ')) {
- splitType = t.Split (' ');
- typeToCompare = splitType[0];
- }
-
- switch (typeToCompare) {
- case "System.Byte": typeToCompare = "byte"; break;
- case "System.SByte": typeToCompare = "sbyte"; break;
- case "System.Int16": typeToCompare = "short"; break;
- case "System.Int32": typeToCompare = "int"; break;
- case "System.Int64": typeToCompare = "long"; break;
-
- case "System.UInt16": typeToCompare = "ushort"; break;
- case "System.UInt32": typeToCompare = "uint"; break;
- case "System.UInt64": typeToCompare = "ulong"; break;
-
- case "System.Single": typeToCompare = "float"; break;
- case "System.Double": typeToCompare = "double"; break;
- case "System.Decimal": typeToCompare = "decimal"; break;
- case "System.Boolean": typeToCompare = "bool"; break;
- case "System.Char": typeToCompare = "char"; break;
- case "System.Void": typeToCompare = "void"; break;
- case "System.String": typeToCompare = "string"; break;
- case "System.Object": typeToCompare = "object"; break;
- }
-
- if (splitType != null) {
- // re-add modreq/modopt if it was there
- splitType[0] = typeToCompare;
- typeToCompare = string.Join (" ", splitType);
- }
- return typeToCompare == t ? null : typeToCompare;
- }
-
- protected override StringBuilder AppendTypeName (StringBuilder buf, TypeReference type, DynamicParserContext context)
- {
- if (context != null && context.TransformFlags != null &&
- (context.TransformFlags.Count == 0 || context.TransformFlags [context.TransformIndex])) {
- context.TransformIndex++;
- return buf.Append ("dynamic");
- }
-
- if (type is GenericParameter)
- return AppendGenericParameterConstraints (buf, (GenericParameter) type, context).Append (type.Name);
- string t = type.FullName;
- if (!t.StartsWith ("System.")) {
- return base.AppendTypeName (buf, type, context);
- }
-
- string s = GetCSharpType (t);
- if (s != null) {
- if (context != null)
- context.TransformIndex++;
- return buf.Append (s);
- }
-
- return base.AppendTypeName (buf, type, context);
- }
-
- private StringBuilder AppendGenericParameterConstraints (StringBuilder buf, GenericParameter type, DynamicParserContext context)
- {
- if (MemberFormatterState != MemberFormatterState.WithinGenericTypeParameters)
- return buf;
- GenericParameterAttributes attrs = type.Attributes;
- bool isout = (attrs & GenericParameterAttributes.Covariant) != 0;
- bool isin = (attrs & GenericParameterAttributes.Contravariant) != 0;
- if (isin)
- buf.Append ("in ");
- else if (isout)
- buf.Append ("out ");
- return buf;
- }
-
- protected override string GetTypeDeclaration (TypeDefinition type)
- {
- string visibility = GetTypeVisibility (type.Attributes);
- if (visibility == null)
- return null;
-
- StringBuilder buf = new StringBuilder ();
-
- buf.Append (visibility);
- buf.Append (" ");
-
- MemberFormatter full = new CSharpFullMemberFormatter ();
-
- if (DocUtils.IsDelegate (type)) {
- buf.Append("delegate ");
- MethodDefinition invoke = type.GetMethod ("Invoke");
- buf.Append (full.GetName (invoke.ReturnType, new DynamicParserContext (invoke.MethodReturnType))).Append (" ");
- buf.Append (GetName (type));
- AppendParameters (buf, invoke, invoke.Parameters);
- AppendGenericTypeConstraints (buf, type);
- buf.Append (";");
-
- return buf.ToString();
- }
-
- if (type.IsAbstract && !type.IsInterface)
- buf.Append("abstract ");
- if (type.IsSealed && !DocUtils.IsDelegate (type) && !type.IsValueType)
- buf.Append("sealed ");
- buf.Replace ("abstract sealed", "static");
-
- buf.Append (GetTypeKind (type));
- buf.Append (" ");
- buf.Append (GetCSharpType (type.FullName) == null
- ? GetName (type)
- : type.Name);
-
- if (!type.IsEnum) {
- TypeReference basetype = type.BaseType;
- if (basetype != null && basetype.FullName == "System.Object" || type.IsValueType) // FIXME
- basetype = null;
-
- List<string> interface_names = DocUtils.GetUserImplementedInterfaces (type)
- .Select (iface => full.GetName (iface))
- .OrderBy (s => s)
- .ToList ();
-
- if (basetype != null || interface_names.Count > 0)
- buf.Append (" : ");
-
- if (basetype != null) {
- buf.Append (full.GetName (basetype));
- if (interface_names.Count > 0)
- buf.Append (", ");
- }
-
- for (int i = 0; i < interface_names.Count; i++){
- if (i != 0)
- buf.Append (", ");
- buf.Append (interface_names [i]);
- }
- AppendGenericTypeConstraints (buf, type);
- }
-
- return buf.ToString ();
- }
-
- static string GetTypeKind (TypeDefinition t)
- {
- if (t.IsEnum)
- return "enum";
- if (t.IsValueType)
- return "struct";
- if (t.IsClass || t.FullName == "System.Enum")
- return "class";
- if (t.IsInterface)
- return "interface";
- throw new ArgumentException(t.FullName);
- }
-
- static string GetTypeVisibility (TypeAttributes ta)
- {
- switch (ta & TypeAttributes.VisibilityMask) {
- case TypeAttributes.Public:
- case TypeAttributes.NestedPublic:
- return "public";
-
- case TypeAttributes.NestedFamily:
- case TypeAttributes.NestedFamORAssem:
- return "protected";
-
- default:
- return null;
- }
- }
-
- protected override StringBuilder AppendGenericTypeConstraints (StringBuilder buf, TypeReference type)
- {
- if (type.GenericParameters.Count == 0)
- return buf;
- return AppendConstraints (buf, type.GenericParameters);
- }
-
- private StringBuilder AppendConstraints (StringBuilder buf, IList<GenericParameter> genArgs)
- {
- foreach (GenericParameter genArg in genArgs) {
- GenericParameterAttributes attrs = genArg.Attributes;
- IList<TypeReference> constraints = genArg.Constraints;
- if (attrs == GenericParameterAttributes.NonVariant && constraints.Count == 0)
- continue;
-
- bool isref = (attrs & GenericParameterAttributes.ReferenceTypeConstraint) != 0;
- bool isvt = (attrs & GenericParameterAttributes.NotNullableValueTypeConstraint) != 0;
- bool isnew = (attrs & GenericParameterAttributes.DefaultConstructorConstraint) != 0;
- bool comma = false;
-
- if (!isref && !isvt && !isnew && constraints.Count == 0)
- continue;
- buf.Append (" where ").Append (genArg.Name).Append (" : ");
- if (isref) {
- buf.Append ("class");
- comma = true;
- }
- else if (isvt) {
- buf.Append ("struct");
- comma = true;
- }
- if (constraints.Count > 0 && !isvt) {
- if (comma)
- buf.Append (", ");
- buf.Append (GetTypeName (constraints [0]));
- for (int i = 1; i < constraints.Count; ++i)
- buf.Append (", ").Append (GetTypeName (constraints [i]));
- }
- if (isnew && !isvt) {
- if (comma)
- buf.Append (", ");
- buf.Append ("new()");
- }
- }
- return buf;
- }
-
- protected override string GetConstructorDeclaration (MethodDefinition constructor)
- {
- StringBuilder buf = new StringBuilder ();
- AppendVisibility (buf, constructor);
- if (buf.Length == 0)
- return null;
-
- buf.Append (' ');
- base.AppendTypeName (buf, constructor.DeclaringType.Name).Append (' ');
- AppendParameters (buf, constructor, constructor.Parameters);
- buf.Append (';');
-
- return buf.ToString ();
- }
-
- protected override string GetMethodDeclaration (MethodDefinition method)
- {
- string decl = base.GetMethodDeclaration (method);
- if (decl != null)
- return decl + ";";
- return null;
- }
-
- protected override StringBuilder AppendMethodName (StringBuilder buf, MethodDefinition method)
- {
- if (DocUtils.IsExplicitlyImplemented (method)) {
- TypeReference iface;
- MethodReference ifaceMethod;
- DocUtils.GetInfoForExplicitlyImplementedMethod (method, out iface, out ifaceMethod);
- return buf.Append (new CSharpMemberFormatter ().GetName (iface))
- .Append ('.')
- .Append (ifaceMethod.Name);
- }
-
- if (method.Name.StartsWith ("op_", StringComparison.Ordinal)) {
- // this is an operator
- switch (method.Name) {
- case "op_Implicit":
- case "op_Explicit":
- buf.Length--; // remove the last space, which assumes a member name is coming
- return buf;
- case "op_Addition":
- case "op_UnaryPlus":
- return buf.Append ("operator +");
- case "op_Subtraction":
- case "op_UnaryNegation":
- return buf.Append ("operator -");
- case "op_Division":
- return buf.Append ("operator /");
- case "op_Multiply":
- return buf.Append ("operator *");
- case "op_Modulus":
- return buf.Append ("operator %");
- case "op_BitwiseAnd":
- return buf.Append ("operator &");
- case "op_BitwiseOr":
- return buf.Append ("operator |");
- case "op_ExclusiveOr":
- return buf.Append ("operator ^");
- case "op_LeftShift":
- return buf.Append ("operator <<");
- case "op_RightShift":
- return buf.Append ("operator >>");
- case "op_LogicalNot":
- return buf.Append ("operator !");
- case "op_OnesComplement":
- return buf.Append ("operator ~");
- case "op_Decrement":
- return buf.Append ("operator --");
- case "op_Increment":
- return buf.Append ("operator ++");
- case "op_True":
- return buf.Append ("operator true");
- case "op_False":
- return buf.Append ("operator false");
- case "op_Equality":
- return buf.Append ("operator ==");
- case "op_Inequality":
- return buf.Append ("operator !=");
- case "op_LessThan":
- return buf.Append ("operator <");
- case "op_LessThanOrEqual":
- return buf.Append ("operator <=");
- case "op_GreaterThan":
- return buf.Append ("operator >");
- case "op_GreaterThanOrEqual":
- return buf.Append ("operator >=");
- default:
- return base.AppendMethodName (buf, method);
- }
- }
- else
- return base.AppendMethodName (buf, method);
- }
-
- protected override StringBuilder AppendGenericMethodConstraints (StringBuilder buf, MethodDefinition method)
- {
- if (method.GenericParameters.Count == 0)
- return buf;
- return AppendConstraints (buf, method.GenericParameters);
- }
-
- protected override string RefTypeModifier {
- get {return "";}
- }
-
- protected override string GetFinalizerName (MethodDefinition method)
- {
- return "~" + method.DeclaringType.Name + " ()";
- }
-
- protected override StringBuilder AppendVisibility (StringBuilder buf, MethodDefinition method)
- {
- if (method == null)
- return buf;
- if (method.IsPublic)
- return buf.Append ("public");
- if (method.IsFamily || method.IsFamilyOrAssembly)
- return buf.Append ("protected");
- return buf;
- }
-
- protected override StringBuilder AppendModifiers (StringBuilder buf, MethodDefinition method)
- {
- string modifiers = String.Empty;
- if (method.IsStatic) modifiers += " static";
- if (method.IsVirtual && !method.IsAbstract) {
- if ((method.Attributes & MethodAttributes.NewSlot) != 0) modifiers += " virtual";
- else modifiers += " override";
- }
- TypeDefinition declType = (TypeDefinition) method.DeclaringType;
- if (method.IsAbstract && !declType.IsInterface) modifiers += " abstract";
- if (method.IsFinal) modifiers += " sealed";
- if (modifiers == " virtual sealed") modifiers = "";
-
- switch (method.Name) {
- case "op_Implicit":
- modifiers += " implicit operator";
- break;
- case "op_Explicit":
- modifiers += " explicit operator";
- break;
- }
-
- return buf.Append (modifiers);
- }
-
- protected override StringBuilder AppendGenericMethod (StringBuilder buf, MethodDefinition method)
- {
- if (method.IsGenericMethod ()) {
- IList<GenericParameter> args = method.GenericParameters;
- if (args.Count > 0) {
- buf.Append ("<");
- buf.Append (args [0].Name);
- for (int i = 1; i < args.Count; ++i)
- buf.Append (",").Append (args [i].Name);
- buf.Append (">");
- }
- }
- return buf;
- }
-
- protected override StringBuilder AppendParameters (StringBuilder buf, MethodDefinition method, IList<ParameterDefinition> parameters)
- {
- return AppendParameters (buf, method, parameters, '(', ')');
- }
-
- private StringBuilder AppendParameters (StringBuilder buf, MethodDefinition method, IList<ParameterDefinition> parameters, char begin, char end)
- {
- buf.Append (begin);
-
- if (parameters.Count > 0) {
- if (DocUtils.IsExtensionMethod (method))
- buf.Append ("this ");
- AppendParameter (buf, parameters [0]);
- for (int i = 1; i < parameters.Count; ++i) {
- buf.Append (", ");
- AppendParameter (buf, parameters [i]);
- }
- }
-
- return buf.Append (end);
- }
-
- private StringBuilder AppendParameter (StringBuilder buf, ParameterDefinition parameter)
- {
- if (parameter.ParameterType is ByReferenceType) {
- if (parameter.IsOut)
- buf.Append ("out ");
- else
- buf.Append ("ref ");
- }
- if (parameter.HasCustomAttributes) {
- var isParams = parameter.CustomAttributes.Any (ca => ca.AttributeType.Name == "ParamArrayAttribute");
- if (isParams)
- buf.AppendFormat ("params ");
- }
- buf.Append (GetTypeName (parameter.ParameterType, new DynamicParserContext (parameter))).Append (" ");
- buf.Append (parameter.Name);
- if (parameter.HasDefault && parameter.IsOptional && parameter.HasConstant) {
- buf.AppendFormat (" = {0}", MDocUpdater.MakeAttributesValueString (parameter.Constant, parameter.ParameterType));
- }
- return buf;
- }
-
- protected override string GetPropertyDeclaration (PropertyDefinition property)
- {
- MethodDefinition method;
-
- string get_visible = null;
- if ((method = property.GetMethod) != null &&
- (DocUtils.IsExplicitlyImplemented (method) ||
- (!method.IsPrivate && !method.IsAssembly && !method.IsFamilyAndAssembly)))
- get_visible = AppendVisibility (new StringBuilder (), method).ToString ();
- string set_visible = null;
- if ((method = property.SetMethod) != null &&
- (DocUtils.IsExplicitlyImplemented (method) ||
- (!method.IsPrivate && !method.IsAssembly && !method.IsFamilyAndAssembly)))
- set_visible = AppendVisibility (new StringBuilder (), method).ToString ();
-
- if ((set_visible == null) && (get_visible == null))
- return null;
-
- string visibility;
- StringBuilder buf = new StringBuilder ();
- if (get_visible != null && (set_visible == null || (set_visible != null && get_visible == set_visible)))
- buf.Append (visibility = get_visible);
- else if (set_visible != null && get_visible == null)
- buf.Append (visibility = set_visible);
- else
- buf.Append (visibility = "public");
-
- // Pick an accessor to use for static/virtual/override/etc. checks.
- method = property.SetMethod;
- if (method == null)
- method = property.GetMethod;
-
- string modifiers = String.Empty;
- if (method.IsStatic) modifiers += " static";
- if (method.IsVirtual && !method.IsAbstract) {
- if ((method.Attributes & MethodAttributes.NewSlot) != 0)
- modifiers += " virtual";
- else
- modifiers += " override";
- }
- TypeDefinition declDef = (TypeDefinition) method.DeclaringType;
- if (method.IsAbstract && !declDef.IsInterface)
- modifiers += " abstract";
- if (method.IsFinal)
- modifiers += " sealed";
- if (modifiers == " virtual sealed")
- modifiers = "";
- buf.Append (modifiers).Append (' ');
-
- buf.Append (GetTypeName (property.PropertyType, new DynamicParserContext (property))).Append (' ');
-
- IEnumerable<MemberReference> defs = property.DeclaringType.GetDefaultMembers ();
- string name = property.Name;
- foreach (MemberReference mi in defs) {
- if (mi == property) {
- name = "this";
- break;
- }
- }
- buf.Append (name == "this" ? name : DocUtils.GetPropertyName (property));
-
- if (property.Parameters.Count != 0) {
- AppendParameters (buf, method, property.Parameters, '[', ']');
- }
-
- buf.Append (" {");
- if (get_visible != null) {
- if (get_visible != visibility)
- buf.Append (' ').Append (get_visible);
- buf.Append (" get;");
- }
- if (set_visible != null) {
- if (set_visible != visibility)
- buf.Append (' ').Append (set_visible);
- buf.Append (" set;");
- }
- buf.Append (" }");
-
- return buf [0] != ' ' ? buf.ToString () : buf.ToString (1, buf.Length-1);
- }
-
- protected override string GetFieldDeclaration (FieldDefinition field)
- {
- TypeDefinition declType = (TypeDefinition) field.DeclaringType;
- if (declType.IsEnum && field.Name == "value__")
- return null; // This member of enums aren't documented.
-
- StringBuilder buf = new StringBuilder ();
- AppendFieldVisibility (buf, field);
- if (buf.Length == 0)
- return null;
-
- if (declType.IsEnum)
- return field.Name;
-
- if (field.IsStatic && !field.IsLiteral)
- buf.Append (" static");
- if (field.IsInitOnly)
- buf.Append (" readonly");
- if (field.IsLiteral)
- buf.Append (" const");
-
- buf.Append (' ').Append (GetTypeName (field.FieldType, new DynamicParserContext (field))).Append (' ');
- buf.Append (field.Name);
- AppendFieldValue (buf, field);
- buf.Append (';');
-
- return buf.ToString ();
- }
-
- static StringBuilder AppendFieldVisibility (StringBuilder buf, FieldDefinition field)
- {
- if (field.IsPublic)
- return buf.Append ("public");
- if (field.IsFamily || field.IsFamilyOrAssembly)
- return buf.Append ("protected");
- return buf;
- }
-
- static StringBuilder AppendFieldValue (StringBuilder buf, FieldDefinition field)
- {
- // enums have a value__ field, which we ignore
- if (((TypeDefinition ) field.DeclaringType).IsEnum ||
- field.DeclaringType.IsGenericType ())
- return buf;
- if (field.HasConstant && field.IsLiteral) {
- object val = null;
- try {
- val = field.Constant;
- } catch {
- return buf;
- }
- if (val == null)
- buf.Append (" = ").Append ("null");
- else if (val is Enum)
- buf.Append (" = ").Append (val.ToString ());
- else if (val is IFormattable) {
- string value = ((IFormattable)val).ToString(null, CultureInfo.InvariantCulture);
- if (val is string)
- value = "\"" + value + "\"";
- buf.Append (" = ").Append (value);
- }
- }
- return buf;
- }
-
- protected override string GetEventDeclaration (EventDefinition e)
- {
- StringBuilder buf = new StringBuilder ();
- if (AppendVisibility (buf, e.AddMethod).Length == 0) {
- return null;
- }
-
- AppendModifiers (buf, e.AddMethod);
-
- buf.Append (" event ");
- buf.Append (GetTypeName (e.EventType, new DynamicParserContext (e.AddMethod.Parameters [0]))).Append (' ');
- buf.Append (e.Name).Append (';');
-
- return buf.ToString ();
- }
-}
-
-public class CSharpMemberFormatter : CSharpFullMemberFormatter {
- protected override StringBuilder AppendNamespace (StringBuilder buf, TypeReference type)
- {
- return buf;
- }
-}
-
-class DocTypeFullMemberFormatter : MemberFormatter {
- public static readonly MemberFormatter Default = new DocTypeFullMemberFormatter ();
-
- protected override char NestedTypeSeparator {
- get {return '+';}
- }
-}
-
-class DocTypeMemberFormatter : DocTypeFullMemberFormatter {
- protected override StringBuilder AppendNamespace (StringBuilder buf, TypeReference type)
- {
- return buf;
- }
-}
-
-class SlashDocMemberFormatter : MemberFormatter {
-
- protected override char[] GenericTypeContainer {
- get {return new char[]{'{', '}'};}
- }
-
- private bool AddTypeCount = true;
-
- private TypeReference genDeclType;
- private MethodReference genDeclMethod;
-
- protected override StringBuilder AppendTypeName (StringBuilder buf, TypeReference type, DynamicParserContext context)
- {
- if (type is GenericParameter) {
- int l = buf.Length;
- if (genDeclType != null) {
- IList<GenericParameter> genArgs = genDeclType.GenericParameters;
- for (int i = 0; i < genArgs.Count; ++i) {
- if (genArgs [i].Name == type.Name) {
- buf.Append ('`').Append (i);
- break;
- }
- }
- }
- if (genDeclMethod != null) {
- IList<GenericParameter> genArgs = null;
- if (genDeclMethod.IsGenericMethod ()) {
- genArgs = genDeclMethod.GenericParameters;
- for (int i = 0; i < genArgs.Count; ++i) {
- if (genArgs [i].Name == type.Name) {
- buf.Append ("``").Append (i);
- break;
- }
- }
- }
- }
- if (genDeclType == null && genDeclMethod == null) {
- // Probably from within an explicitly implemented interface member,
- // where CSC uses parameter names instead of indices (why?), e.g.
- // MyList`2.Mono#DocTest#Generic#IFoo{A}#Method``1(`0,``0) instead of
- // MyList`2.Mono#DocTest#Generic#IFoo{`0}#Method``1(`0,``0).
- buf.Append (type.Name);
- }
- if (buf.Length == l) {
- throw new Exception (string.Format (
- "Unable to translate generic parameter {0}; genDeclType={1}, genDeclMethod={2}",
- type.Name, genDeclType, genDeclMethod));
- }
- }
- else {
- base.AppendTypeName (buf, type, context);
- if (AddTypeCount) {
- int numArgs = type.GenericParameters.Count;
- if (type.DeclaringType != null)
- numArgs -= type.GenericParameters.Count;
- if (numArgs > 0) {
- buf.Append ('`').Append (numArgs);
- }
- }
- }
- return buf;
- }
-
- protected override StringBuilder AppendArrayModifiers (StringBuilder buf, ArrayType array)
- {
- buf.Append (ArrayDelimeters [0]);
- int rank = array.Rank;
- if (rank > 1) {
- buf.Append ("0:");
- for (int i = 1; i < rank; ++i) {
- buf.Append (",0:");
- }
- }
- return buf.Append (ArrayDelimeters [1]);
- }
-
- protected override StringBuilder AppendGenericType (StringBuilder buf, TypeReference type, DynamicParserContext context)
- {
- if (!AddTypeCount)
- base.AppendGenericType (buf, type, context);
- else
- AppendType (buf, type, context);
- return buf;
- }
-
- private StringBuilder AppendType (StringBuilder buf, TypeReference type, DynamicParserContext context)
- {
- List<TypeReference> decls = DocUtils.GetDeclaringTypes (type);
- bool insertNested = false;
- int prevParamCount = 0;
- foreach (var decl in decls) {
- if (insertNested)
- buf.Append (NestedTypeSeparator);
- insertNested = true;
- base.AppendTypeName (buf, decl, context);
- int argCount = DocUtils.GetGenericArgumentCount (decl);
- int numArgs = argCount - prevParamCount;
- prevParamCount = argCount;
- if (numArgs > 0)
- buf.Append ('`').Append (numArgs);
- }
- return buf;
- }
-
- protected override string GetConstructorName (MethodReference constructor)
- {
- return GetMethodDefinitionName (constructor, "#ctor");
- }
-
- protected override string GetMethodName (MethodReference method)
- {
- string name = null;
- MethodDefinition methodDef = method as MethodDefinition;
- if (methodDef == null || !DocUtils.IsExplicitlyImplemented (methodDef))
- name = method.Name;
- else {
- TypeReference iface;
- MethodReference ifaceMethod;
- DocUtils.GetInfoForExplicitlyImplementedMethod (methodDef, out iface, out ifaceMethod);
- AddTypeCount = false;
- name = GetTypeName (iface) + "." + ifaceMethod.Name;
- AddTypeCount = true;
- }
- return GetMethodDefinitionName (method, name);
- }
-
- private string GetMethodDefinitionName (MethodReference method, string name)
- {
- StringBuilder buf = new StringBuilder ();
- buf.Append (GetTypeName (method.DeclaringType));
- buf.Append ('.');
- buf.Append (name.Replace (".", "#"));
- if (method.IsGenericMethod ()) {
- IList<GenericParameter> genArgs = method.GenericParameters;
- if (genArgs.Count > 0)
- buf.Append ("``").Append (genArgs.Count);
- }
- IList<ParameterDefinition> parameters = method.Parameters;
- try {
- genDeclType = method.DeclaringType;
- genDeclMethod = method;
- AppendParameters (buf, method.DeclaringType.GenericParameters, parameters);
- }
- finally {
- genDeclType = null;
- genDeclMethod = null;
- }
- return buf.ToString ();
- }
-
- private StringBuilder AppendParameters (StringBuilder buf, IList<GenericParameter> genArgs, IList<ParameterDefinition> parameters)
- {
- if (parameters.Count == 0)
- return buf;
-
- buf.Append ('(');
-
- AppendParameter (buf, genArgs, parameters [0]);
- for (int i = 1; i < parameters.Count; ++i) {
- buf.Append (',');
- AppendParameter (buf, genArgs, parameters [i]);
- }
-
- return buf.Append (')');
- }
-
- private StringBuilder AppendParameter (StringBuilder buf, IList<GenericParameter> genArgs, ParameterDefinition parameter)
- {
- AddTypeCount = false;
- buf.Append (GetTypeName (parameter.ParameterType));
- AddTypeCount = true;
- return buf;
- }
-
- protected override string GetPropertyName (PropertyReference property)
- {
- string name = null;
-
- PropertyDefinition propertyDef = property as PropertyDefinition;
- MethodDefinition method = null;
- if (propertyDef != null)
- method = propertyDef.GetMethod ?? propertyDef.SetMethod;
- if (method != null && !DocUtils.IsExplicitlyImplemented (method))
- name = property.Name;
- else {
- TypeReference iface;
- MethodReference ifaceMethod;
- DocUtils.GetInfoForExplicitlyImplementedMethod (method, out iface, out ifaceMethod);
- AddTypeCount = false;
- name = string.Join ("#", new string[]{
- GetTypeName (iface).Replace (".", "#"),
- DocUtils.GetMember (property.Name)
- });
- AddTypeCount = true;
- }
-
- StringBuilder buf = new StringBuilder ();
- buf.Append (GetName (property.DeclaringType));
- buf.Append ('.');
- buf.Append (name);
- IList<ParameterDefinition> parameters = property.Parameters;
- if (parameters.Count > 0) {
- genDeclType = property.DeclaringType;
- buf.Append ('(');
- IList<GenericParameter> genArgs = property.DeclaringType.GenericParameters;
- AppendParameter (buf, genArgs, parameters [0]);
- for (int i = 1; i < parameters.Count; ++i) {
- buf.Append (',');
- AppendParameter (buf, genArgs, parameters [i]);
- }
- buf.Append (')');
- genDeclType = null;
- }
- return buf.ToString ();
- }
-
- protected override string GetFieldName (FieldReference field)
- {
- return string.Format ("{0}.{1}",
- GetName (field.DeclaringType), field.Name);
- }
-
- protected override string GetEventName (EventReference e)
- {
- return string.Format ("{0}.{1}",
- GetName (e.DeclaringType), e.Name);
- }
-
- protected override string GetTypeDeclaration (TypeDefinition type)
- {
- string name = GetName (type);
- if (type == null)
- return null;
- return "T:" + name;
- }
-
- protected override string GetConstructorDeclaration (MethodDefinition constructor)
- {
- string name = GetName (constructor);
- if (name == null)
- return null;
- return "M:" + name;
- }
-
- protected override string GetMethodDeclaration (MethodDefinition method)
- {
- string name = GetName (method);
- if (name == null)
- return null;
- if (method.Name == "op_Implicit" || method.Name == "op_Explicit") {
- genDeclType = method.DeclaringType;
- genDeclMethod = method;
- name += "~" + GetName (method.ReturnType);
- genDeclType = null;
- genDeclMethod = null;
- }
- return "M:" + name;
- }
-
- protected override string GetPropertyDeclaration (PropertyDefinition property)
- {
- string name = GetName (property);
- if (name == null)
- return null;
- return "P:" + name;
- }
-
- protected override string GetFieldDeclaration (FieldDefinition field)
- {
- string name = GetName (field);
- if (name == null)
- return null;
- return "F:" + name;
- }
-
- protected override string GetEventDeclaration (EventDefinition e)
- {
- string name = GetName (e);
- if (name == null)
- return null;
- return "E:" + name;
- }
-}
-
-class FileNameMemberFormatter : SlashDocMemberFormatter {
- protected override StringBuilder AppendNamespace (StringBuilder buf, TypeReference type)
- {
- return buf;
- }
-
- protected override char NestedTypeSeparator {
- get {return '+';}
- }
-}
-
-class ResolvedTypeInfo {
- TypeDefinition typeDef;
-
- public ResolvedTypeInfo (TypeReference value) {
- Reference = value;
- }
-
- public TypeReference Reference { get; private set; }
-
- public TypeDefinition Definition {
- get {
- if (typeDef == null) {
- typeDef = Reference.Resolve ();
- }
- return typeDef;
- }
- }
-}
-
-/// <summary>Formats attribute values. Should return true if it is able to format the value.</summary>
-class AttributeValueFormatter {
- public virtual bool TryFormatValue (object v, ResolvedTypeInfo type, out string returnvalue)
- {
- TypeReference valueType = type.Reference;
- if (v == null) {
- returnvalue = "null";
- return true;
- }
- if (valueType.FullName == "System.Type") {
- var vTypeRef = v as TypeReference;
- if (vTypeRef != null)
- returnvalue = "typeof(" + NativeTypeManager.GetTranslatedName (vTypeRef) + ")"; // TODO: drop NS handling
- else
- returnvalue = "typeof(" + v.ToString () + ")";
-
- return true;
- }
- if (valueType.FullName == "System.String") {
- returnvalue = "\"" + v.ToString () + "\"";
- return true;
- }
- if (valueType.FullName == "System.Char") {
- returnvalue = "'" + v.ToString () + "'";
- return true;
- }
- if (v is Boolean) {
- returnvalue = (bool)v ? "true" : "false";
- return true;
- }
-
- TypeDefinition valueDef = type.Definition;
- if (valueDef == null || !valueDef.IsEnum) {
- returnvalue = v.ToString ();
- return true;
- }
-
- string typename = MDocUpdater.GetDocTypeFullName (valueType);
- var values = MDocUpdater.GetEnumerationValues (valueDef);
- long c = MDocUpdater.ToInt64 (v);
- if (values.ContainsKey (c)) {
- returnvalue = typename + "." + values [c];
- return true;
- }
-
- returnvalue = null;
- return false;
- }
-}
-
-/// <summary>The final value formatter in the pipeline ... if no other formatter formats the value,
-/// then this one will serve as the default implementation.</summary>
-class DefaultAttributeValueFormatter : AttributeValueFormatter {
- public override bool TryFormatValue (object v, ResolvedTypeInfo type, out string returnvalue)
- {
- returnvalue = "(" + MDocUpdater.GetDocTypeFullName (type.Reference) + ") " + v.ToString ();
- return true;
- }
-}
-
-/// <summary>Flags enum formatter that assumes powers of two values.</summary>
-/// <remarks>As described here: https://msdn.microsoft.com/en-us/library/vstudio/ms229062(v=vs.100).aspx</remarks>
-class StandardFlagsEnumFormatter : AttributeValueFormatter {
- public override bool TryFormatValue (object v, ResolvedTypeInfo type, out string returnvalue)
- {
- TypeReference valueType = type.Reference;
- TypeDefinition valueDef = type.Definition;
- if (valueDef.CustomAttributes.Any (ca => ca.AttributeType.FullName == "System.FlagsAttribute")) {
-
- string typename = MDocUpdater.GetDocTypeFullName (valueType);
- var values = MDocUpdater.GetEnumerationValues (valueDef);
- long c = MDocUpdater.ToInt64 (v);
- returnvalue = string.Join (" | ",
- (from i in values.Keys
- where (c & i) == i && i != 0
- select typename + "." + values [i])
- .DefaultIfEmpty (c.ToString ()).ToArray ());
-
- return true;
- }
-
- returnvalue = null;
- return false;
- }
-}
-
-/// <summary>A custom formatter for the ObjCRuntime.Platform enumeration.</summary>
-class ApplePlatformEnumFormatter : AttributeValueFormatter {
- public override bool TryFormatValue (object v, ResolvedTypeInfo type, out string returnvalue)
- {
- TypeReference valueType = type.Reference;
- string typename = MDocUpdater.GetDocTypeFullName (valueType);
- TypeDefinition valueDef = type.Definition;
- if (typename.Contains ("ObjCRuntime.Platform") && valueDef.CustomAttributes.Any (ca => ca.AttributeType.FullName == "System.FlagsAttribute")) {
-
- var values = MDocUpdater.GetEnumerationValues (valueDef);
- long c = MDocUpdater.ToInt64 (v);
-
- returnvalue = Format (c, values, typename);
- return true;
- }
-
- returnvalue = null;
- return false;
- }
-
- string Format (long c, IDictionary<long, string> values, string typename)
- {
- int iosarch, iosmajor, iosminor, iossubminor;
- int macarch, macmajor, macminor, macsubminor;
- GetEncodingiOS (c, out iosarch, out iosmajor, out iosminor, out iossubminor);
- GetEncodingMac ((ulong)c, out macarch, out macmajor, out macminor, out macsubminor);
-
- if (iosmajor == 0 & iosminor == 0 && iossubminor == 0) {
- return FormatValues ("Mac", macarch, macmajor, macminor, macsubminor);
- }
-
- if (macmajor == 0 & macminor == 0 && macsubminor == 0) {
- return FormatValues ("iOS", iosarch, iosmajor, iosminor, iossubminor);
- }
-
- return string.Format ("(Platform){0}", c);
- }
-
- string FormatValues (string plat, int arch, int major, int minor, int subminor)
- {
- string archstring = "";
- switch (arch) {
- case 1:
- archstring = "32";
- break;
- case 2:
- archstring = "64";
- break;
- }
- return string.Format ("Platform.{4}_{0}_{1}{2} | Platform.{4}_Arch{3}",
- major,
- minor,
- subminor == 0 ? "" : "_" + subminor.ToString (),
- archstring,
- plat
- );
- }
-
- void GetEncodingiOS (long entireLong, out int archindex, out int major, out int minor, out int subminor)
- {
- long lowerBits = entireLong & 0xffffffff;
- int lowerBitsAsInt = (int) lowerBits;
- GetEncoding (lowerBitsAsInt, out archindex, out major, out minor, out subminor);
- }
-
- void GetEncodingMac (ulong entireLong, out int archindex, out int major, out int minor, out int subminor)
- {
- ulong higherBits = entireLong & 0xffffffff00000000;
- int higherBitsAsInt = (int) ((higherBits) >> 32);
- GetEncoding (higherBitsAsInt, out archindex, out major, out minor, out subminor);
- }
-
- void GetEncoding (Int32 encodedBits, out int archindex, out int major, out int minor, out int subminor)
- {
- // format is AAJJNNSS
- archindex = (int)((encodedBits & 0xFF000000) >> 24);
- major = (int)((encodedBits & 0x00FF0000) >> 16);
- minor = (int)((encodedBits & 0x0000FF00) >> 8);
- subminor = (int)((encodedBits & 0x000000FF) >> 0);
- }
-}
-} \ No newline at end of file
diff --git a/mdoc/mdoc.Test/FormatterTests.cs b/mdoc/mdoc.Test/FormatterTests.cs
index 799ad138..30a98133 100644
--- a/mdoc/mdoc.Test/FormatterTests.cs
+++ b/mdoc/mdoc.Test/FormatterTests.cs
@@ -7,6 +7,8 @@ using Mono.Cecil;
using mdoc.Test.SampleClasses;
using System.Linq.Expressions;
+using Mono.Documentation.Updater;
+
namespace mdoc.Test
{
[TestFixture ()]
diff --git a/mdoc/mdoc.csproj b/mdoc/mdoc.csproj
index ce716613..8bc16065 100644
--- a/mdoc/mdoc.csproj
+++ b/mdoc/mdoc.csproj
@@ -51,6 +51,36 @@
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup>
+ <Compile Include="Mono.Documentation\Updater\Formatters\ApplePlatformEnumFormatter.cs" />
+ <Compile Include="Mono.Documentation\Updater\Formatters\StandardFlagsEnumFormatter.cs" />
+ <Compile Include="Mono.Documentation\Updater\Formatters\DefaultAttributeValueFormatter.cs" />
+ <Compile Include="Mono.Documentation\Updater\Formatters\AttributeValueFormatter.cs" />
+ <Compile Include="Mono.Documentation\Updater\ResolvedTypeInfo.cs" />
+ <Compile Include="Mono.Documentation\Updater\Formatters\FileNameMemberFormatter.cs" />
+ <Compile Include="Mono.Documentation\Updater\Formatters\SlashDocMemberFormatter.cs" />
+ <Compile Include="Mono.Documentation\Updater\Formatters\DocTypeMemberFormatter.cs" />
+ <Compile Include="Mono.Documentation\Updater\Formatters\DocTypeFullMemberFormatter.cs" />
+ <Compile Include="Mono.Documentation\Updater\Formatters\CSharpMemberFormatter.cs" />
+ <Compile Include="Mono.Documentation\Updater\Formatters\CSharpFullMemberFormatter.cs" />
+ <Compile Include="Mono.Documentation\Updater\Formatters\CSharpNativeTypeMemberFormatter.cs" />
+ <Compile Include="Mono.Documentation\Updater\Formatters\ILNativeTypeMemberFormatter.cs" />
+ <Compile Include="Mono.Documentation\Updater\Formatters\ILMemberFormatter.cs" />
+ <Compile Include="Mono.Documentation\Updater\Formatters\ILFullMemberFormatter.cs" />
+ <Compile Include="Mono.Documentation\Updater\Formatters\DocIdFormatter.cs" />
+ <Compile Include="Mono.Documentation\Updater\Formatters\MemberFormatter.cs" />
+ <Compile Include="Mono.Documentation\Updater\MemberFormatterState.cs" />
+ <Compile Include="Mono.Documentation\Updater\DynamicParserContext.cs" />
+ <Compile Include="Mono.Documentation\Updater\DocumentationMember.cs" />
+ <Compile Include="Mono.Documentation\Updater\EcmaDocumentationImporter.cs" />
+ <Compile Include="Mono.Documentation\Updater\MsxdocDocumentationImporter.cs" />
+ <Compile Include="Mono.Documentation\Updater\DocumentationImporter.cs" />
+ <Compile Include="Mono.Documentation\Updater\EcmaDocumentationEnumerator.cs" />
+ <Compile Include="Mono.Documentation\Updater\DocumentationEnumerator.cs" />
+ <Compile Include="Mono.Documentation\Updater\DocsNodeInfo.cs" />
+ <Compile Include="Mono.Documentation\Util\ApiStyle.cs" />
+ <Compile Include="Mono.Documentation\Updater\DocUtils.cs" />
+ <Compile Include="Mono.Documentation\Util\CecilExtensions.cs" />
+ <Compile Include="Mono.Documentation\Util\NativeTypeManager.cs" />
<Compile Include="Mono.Rocks\ObjectRocks.cs" />
<Compile Include="Mono.Rocks\StreamRocks.cs" />
<Compile Include="Mono.Documentation\assembler.cs" />
@@ -58,7 +88,6 @@
<Compile Include="Mono.Documentation\ecmadoc.cs" />
<Compile Include="Mono.Documentation\mdoc.cs" />
<Compile Include="Mono.Documentation\MdocFile.cs" />
- <Compile Include="Mono.Documentation\monodocer.cs" />
<Compile Include="Mono.Documentation\monodocs2html.cs" />
<Compile Include="Mono.Documentation\monodocs2slashdoc.cs" />
<Compile Include="Mono.Documentation\msitomsx.cs" />
@@ -71,11 +100,12 @@
<Compile Include="Mono.Documentation\frameworksbootstrapper.cs" />
<Compile Include="Consts.cs" />
<Compile Include="Options.cs" />
- <Compile Include="Mono.Documentation\Frameworks\FrameworkIndex.cs" />
- <Compile Include="Mono.Documentation\Frameworks\FrameworkEntry.cs" />
- <Compile Include="Mono.Documentation\Frameworks\FrameworkTypeEntry.cs" />
- <Compile Include="Mono.Documentation\Frameworks\AssemblySet.cs" />
- <Compile Include="Mono.Documentation\Frameworks\UwpResolver.cs" />
+ <Compile Include="Mono.Documentation\Updater\Frameworks\FrameworkIndex.cs" />
+ <Compile Include="Mono.Documentation\Updater\Frameworks\FrameworkEntry.cs" />
+ <Compile Include="Mono.Documentation\Updater\Frameworks\FrameworkTypeEntry.cs" />
+ <Compile Include="Mono.Documentation\Updater\Frameworks\AssemblySet.cs" />
+ <Compile Include="Mono.Documentation\Updater\Frameworks\UwpResolver.cs" />
+ <Compile Include="Mono.Documentation\MDocUpdater.cs" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Resources\defaulttemplate.xsl">