using System;
using System.Collections;
using System.Collections.Generic;
+using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
namespace Mono.Documentation {
-class MDocUpdaterOptions
-{
- public string path = null;
- public string updateto = null;
- public List<string> assembly = null;
- public List<string> type = null;
- public string @namespace = null;
- public bool delete = false;
- public bool overrides = true;
- public bool ignoremembers = false;
- public bool ignore_extra_docs = false;
- public string name;
- public string import;
- public bool pretty = true;
- public string since;
- public bool show_exceptions;
-}
-
class MDocUpdater : MDocCommand
{
+ string srcPath;
+ List<AssemblyDefinition> assemblies;
- static string srcPath;
- static List<AssemblyDefinition> assemblies;
+ bool delete;
+ bool show_exceptions;
+ bool no_assembly_versions;
+ ExceptionLocations? exceptions;
- static bool nooverrides = true, delete = false, ignoremembers = false;
- static bool pretty = false;
- static bool show_exceptions = false;
-
- static int additions = 0, deletions = 0;
+ int additions = 0, deletions = 0;
- static string name;
static XmlDocument slashdocs;
- static XmlReader ecmadocs;
+ XmlReader ecmadocs;
- static string since;
+ string since;
- static MemberFormatter csharpFullFormatter = new CSharpFullMemberFormatter ();
- static MemberFormatter csharpFormatter = new CSharpMemberFormatter ();
- static MemberFormatter docTypeFormatter = new DocTypeMemberFormatter ();
- static MemberFormatter slashdocFormatter = new SlashDocMemberFormatter ();
- static MemberFormatter filenameFormatter = new FileNameMemberFormatter ();
+ static readonly MemberFormatter csharpFullFormatter = new CSharpFullMemberFormatter ();
+ static readonly MemberFormatter csharpFormatter = new CSharpMemberFormatter ();
+ static readonly MemberFormatter docTypeFormatter = new DocTypeMemberFormatter ();
+ static readonly MemberFormatter slashdocFormatter = new SlashDocMemberFormatter ();
+ static readonly MemberFormatter filenameFormatter = new FileNameMemberFormatter ();
- static MyXmlNodeList extensionMethods = new MyXmlNodeList ();
+ MyXmlNodeList extensionMethods = new MyXmlNodeList ();
public override void Run (IEnumerable<string> args)
{
- var opts = new MDocUpdaterOptions {
- overrides = true,
- pretty = true,
- show_exceptions = DebugOutput,
- };
-
- opts.type = new List<string> ();
+ show_exceptions = DebugOutput;
+ string import = null;
+ var types = new List<string> ();
var p = new OptionSet () {
- { "o|out=",
- "Root {DIRECTORY} to generate/update documentation.",
- v => opts.path = v },
- { "i|import=",
- "Import documentation from {FILE}.",
- v => opts.import = v },
{ "delete",
"Delete removed members from the XML files.",
- v => opts.delete = v != null },
+ 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" +
+ "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 "no-assembly-versions":
+ no_assembly_versions = true;
+ break;
+ default:
+ throw new Exception ("Unsupported flag `" + v + "'.");
+ }
+ } },
+ { "fno-assembly-versions",
+ "Do not generate //AssemblyVersion elements.",
+ v => no_assembly_versions = v != null },
+ { "i|import=",
+ "Import documentation from {FILE}.",
+ v => import = v },
+ { "o|out=",
+ "Root {DIRECTORY} to generate/update documentation.",
+ v => srcPath = v },
{ "since=",
- "Manually specify the assembly version that new members were added in.",
- v => opts.since = v },
+ "Manually specify the assembly {VERSION} that new members were added in.",
+ v => since = v },
{ "type=",
"Only update documentation for {TYPE}.",
- v => opts.type.Add (v) },
+ v => types.Add (v) },
};
- opts.assembly = Parse (p, args, "update",
+ var assemblies = Parse (p, args, "update",
"[OPTIONS]+ ASSEMBLIES",
"Create or update documentation from ASSEMBLIES.");
- if (opts.assembly == null)
+ if (assemblies == null)
return;
- if (opts.assembly.Count == 0)
+ if (assemblies.Count == 0)
Error ("No assemblies specified.");
- Run (opts);
- opts.name = ""; // remove warning about unused member
- }
-
- static void Run (MDocUpdaterOptions opts)
- {
- nooverrides = !opts.overrides;
- delete = opts.delete;
- ignoremembers = opts.ignoremembers;
- name = opts.name;
- pretty = opts.pretty;
- since = opts.since;
- show_exceptions = opts.show_exceptions;
-
- try {
- // PARSE BASIC OPTIONS AND LOAD THE ASSEMBLY TO DOCUMENT
-
- if (opts.path == null)
- throw new InvalidOperationException("The path option is required.");
-
- srcPath = opts.path;
+ // PARSE BASIC OPTIONS AND LOAD THE ASSEMBLY TO DOCUMENT
+
+ if (srcPath == null)
+ throw new InvalidOperationException("The --out option is required.");
+
+ this.assemblies = assemblies.Select (a => LoadAssembly (a)).ToList ();
- if (opts.type != null && opts.type.Count > 0 && opts.@namespace != null)
- throw new InvalidOperationException("You cannot specify both 'type' and 'namespace'.");
-
- if (opts.assembly == null)
- throw new InvalidOperationException("The assembly option is required.");
-
- assemblies = opts.assembly.Select (a => LoadAssembly (a)).ToList ();
-
- if (opts.import != null && ecmadocs == null && slashdocs == null) {
- try {
- XmlReader r = new XmlTextReader (opts.import);
- if (r.Read ()) {
- while (r.NodeType != XmlNodeType.Element) {
- if (!r.Read ())
- throw new Exception ("Unable to read XML file: " +
- opts.import);
- }
- if (r.LocalName == "doc") {
- slashdocs = new XmlDocument();
- slashdocs.Load (opts.import);
- }
- else if (r.LocalName == "Libraries") {
- ecmadocs = new XmlTextReader (opts.import);
- }
- else
- throw new Exception ("Unsupported XML format within " + opts.import);
+ if (import != null && ecmadocs == null && slashdocs == null) {
+ try {
+ XmlReader r = new XmlTextReader (import);
+ if (r.Read ()) {
+ while (r.NodeType != XmlNodeType.Element) {
+ if (!r.Read ())
+ Error ("Unable to read XML file: {0}.", import);
+ }
+ if (r.LocalName == "doc") {
+ slashdocs = new XmlDocument();
+ slashdocs.Load (import);
+ }
+ else if (r.LocalName == "Libraries") {
+ ecmadocs = new XmlTextReader (import);
}
- r.Close ();
- } catch (Exception e) {
- Error ("Could not load XML file: {0}", e.Message);
- Environment.ExitCode = 1;
- return;
+ else
+ Error ("Unsupported XML format within {0}.", import);
}
+ r.Close ();
+ } catch (Exception e) {
+ Environment.ExitCode = 1;
+ Error ("Could not load XML file: {0}.", e.Message);
}
-
- // PERFORM THE UPDATES
-
- string dest_dir = opts.updateto != null ? opts.updateto : opts.path;
- if (opts.type != null && opts.type.Count > 0)
- DoUpdateTypes(opts.path, opts.type, dest_dir);
- else if (opts.@namespace != null)
- DoUpdateNS (opts.@namespace, Path.Combine (opts.path, opts.@namespace),
- Path.Combine (dest_dir, opts.@namespace));
- else
- DoUpdateAssemblies(opts.path, dest_dir);
-
- } catch (InvalidOperationException error) {
- Error (opts.show_exceptions ? error.ToString () : error.Message);
- Environment.ExitCode = 1;
- return;
-
- } catch (System.IO.IOException error) {
- Error (opts.show_exceptions ? error.ToString () : error.Message);
- Environment.ExitCode = 1;
- return;
-
- } catch (Exception error) {
- Error (opts.show_exceptions ? error.ToString () : error.Message);
- Environment.ExitCode = 1;
}
+
+ // PERFORM THE UPDATES
+
+ if (types.Count > 0)
+ DoUpdateTypes (srcPath, types, srcPath);
+#if false
+ else if (opts.@namespace != null)
+ DoUpdateNS (opts.@namespace, Path.Combine (opts.path, opts.@namespace),
+ Path.Combine (dest_dir, opts.@namespace));
+#endif
+ else
+ DoUpdateAssemblies (srcPath, srcPath);
Console.WriteLine("Members Added: {0}, Members Deleted: {1}", additions, deletions);
}
- private static new void Error (string format, params object[] args)
+ static ExceptionLocations ParseExceptionLocations (string s)
+ {
+ ExceptionLocations loc = ExceptionLocations.Member;
+ if (s == null)
+ return loc;
+ foreach (var type in s.Split (',')) {
+ switch (type) {
+ case "asm": loc |= ExceptionLocations.Assembly; break;
+ case "depasm": loc |= ExceptionLocations.DependentAssemblies; break;
+ case "all": loc = ExceptionLocations.All; break;
+ default: throw new NotSupportedException ("Unsupported --exceptions value: " + type);
+ }
+ }
+ return loc;
+ }
+
+ private void Warning (string format, params object[] args)
{
- Console.Error.Write ("monodocer: ");
- Console.Error.WriteLine (format, args);
+ Message (TraceLevel.Warning, "mdoc: " + format, args);
}
private static AssemblyDefinition LoadAssembly (string name)
if (assembly == null)
throw new InvalidOperationException("Assembly " + name + " not found.");
+ var r = assembly.Resolver as BaseAssemblyResolver;
+ if (r != null && name.Contains (Path.DirectorySeparatorChar)) {
+ r.AddSearchDirectory (Path.GetDirectoryName (name));
+ }
return assembly;
}
}
}
- private static XmlDocument CreateIndexStub() {
+ private XmlDocument CreateIndexStub()
+ {
XmlDocument index = new XmlDocument();
XmlElement index_root = index.CreateElement("Overview");
}
}
- public static void DoUpdateTypes (string basepath, List<string> typenames, string dest)
+ public void DoUpdateTypes (string basepath, List<string> typenames, string dest)
{
var found = new HashSet<string> ();
foreach (AssemblyDefinition assembly in assemblies) {
throw new InvalidOperationException("Type(s) not found: " + string.Join (", ", notFound.ToArray ()));
}
- public static string DoUpdateType(TypeDefinition type, string basepath, string dest, XmlReader ecmaDocsType)
+ public string DoUpdateType (TypeDefinition type, string basepath, string dest, XmlReader ecmaDocsType)
{
if (type.Namespace == null)
- Error ("warning: The type `{0}' is in the root namespace. This may cause problems with display within monodoc.",
+ 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;
if (file.Exists) {
// Update
XmlDocument basefile = new XmlDocument();
- if (!pretty) basefile.PreserveWhitespace = true;
try {
basefile.Load(typefile);
} catch (Exception e) {
return reltypefile;
}
- public static void DoUpdateNS(string ns, string nspath, string outpath) {
+ public void DoUpdateNS (string ns, string nspath, string outpath)
+ {
Dictionary<TypeDefinition, object> seenTypes = new Dictionary<TypeDefinition,object> ();
AssemblyDefinition assembly = assemblies [0];
foreach (System.IO.FileInfo file in new System.IO.DirectoryInfo(nspath).GetFiles("*.xml")) {
XmlDocument basefile = new XmlDocument();
- if (!pretty) basefile.PreserveWhitespace = true;
string typefile = Path.Combine(nspath, file.Name);
try {
basefile.Load(typefile);
GetTypeFileName (basefile.SelectSingleNode("Type/@FullName").InnerText);
TypeDefinition type = assembly.GetType(typename);
if (type == null) {
- Error ("Type no longer in assembly: " + typename);
+ Warning ("Type no longer in assembly: " + typename);
continue;
}
return filename.ToString ();
}
- private static void AddIndexAssembly (AssemblyDefinition assembly, XmlElement parent)
+ private void AddIndexAssembly (AssemblyDefinition assembly, XmlElement parent)
{
XmlElement index_assembly = parent.OwnerDocument.CreateElement("Assembly");
index_assembly.SetAttribute ("Name", assembly.Name.Name);
parent.AppendChild(index_assembly);
}
- private static void DoUpdateAssemblies (string source, string dest)
+ private void DoUpdateAssemblies (string source, string dest)
{
string indexfile = dest + "/index.xml";
XmlDocument index;
index = CreateIndexStub();
}
- if (name == null) {
- string defaultTitle = "Untitled";
- if (assemblies.Count == 1)
- defaultTitle = assemblies[0].Name.Name;
- WriteElementInitialText(index.DocumentElement, "Title", defaultTitle);
- } else {
- WriteElementText(index.DocumentElement, "Title", name);
- }
+ string defaultTitle = "Untitled";
+ if (assemblies.Count == 1)
+ defaultTitle = assemblies[0].Name.Name;
+ WriteElementInitialText(index.DocumentElement, "Title", defaultTitle);
XmlElement index_types = WriteElement(index.DocumentElement, "Types");
XmlElement index_assemblies = WriteElement(index.DocumentElement, "Assemblies");
private static char[] InvalidFilenameChars = {'\\', '/', ':', '*', '?', '"', '<', '>', '|'};
- private static void DoUpdateAssembly (AssemblyDefinition assembly, XmlElement index_types, string source, string dest, HashSet<string> goodfiles)
+ private void DoUpdateAssembly (AssemblyDefinition assembly, XmlElement index_types, string source, string dest, HashSet<string> goodfiles)
{
foreach (DocsTypeInfo docTypeInfo in GetTypes (assembly, null)) {
TypeDefinition type = docTypeInfo.Type;
}
}
- static IEnumerable<Mono.Documentation.MDocUpdater.DocsTypeInfo> GetTypes (AssemblyDefinition assembly, List<string> forTypes)
+ IEnumerable<Mono.Documentation.MDocUpdater.DocsTypeInfo> GetTypes (AssemblyDefinition assembly, List<string> forTypes)
{
HashSet<string> seen = null;
if (forTypes != null)
}
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 ["Name"].Value.CompareTo (y.Attributes ["Name"].Value);
+ return x.Attributes [attribute].Value.CompareTo (y.Attributes [attribute].Value);
}
}
return true;
}
- private static void CleanupFiles (string dest, HashSet<string> goodfiles)
+ 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("*")) {
);
}
- private static string[] GetAssemblyVersions ()
+ private string[] GetAssemblyVersions ()
{
return (from a in assemblies select GetAssemblyVersion (a)).ToArray ();
}
n.ParentNode.RemoveChild (n);
}
- private static void CleanupExtensions (XmlElement index_types)
+ private void CleanupExtensions (XmlElement index_types)
{
XmlNode e = index_types.SelectSingleNode ("/Overview/ExtensionMethods");
if (extensionMethods.Count == 0) {
static readonly XmlNodeComparer DefaultExtensionMethodComparer = new ExtensionMethodComparer ();
- public static void DoUpdateType2 (string message, XmlDocument basefile, TypeDefinition type, string output, bool insertSince, XmlReader ecmaDocsType)
+ public void DoUpdateType2 (string message, XmlDocument basefile, TypeDefinition type, string output, bool insertSince, XmlReader ecmaDocsType)
{
Console.WriteLine(message + ": " + type.FullName);
// 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.
- if (!ignoremembers) {
+ if (true) {
MyXmlNodeList todelete = new MyXmlNodeList ();
foreach (DocsNodeInfo info in GetDocumentationMembers (basefile, type, ecmaDocsType)) {
XmlElement oldmember = info.Node;
// Interface implementations and overrides are deleted from the docs
// unless the overrides option is given.
- if (oldmember2 != null && (!IsNew(oldmember2) || sig == null))
+ if (oldmember2 != null && sig == null)
oldmember2 = null;
// Deleted (or signature changed)
else if (DefaultMemberComparer.Compare (oldmember, seenmembers [sig]) == 0)
DeleteMember ("Duplicate Member Found", output, oldmember, todelete);
else
- Error ("TODO: found a duplicate member '{0}', but it's not identical to the prior member found!", sig);
+ Warning ("TODO: found a duplicate member '{0}', but it's not identical to the prior member found!", sig);
continue;
}
oldmember.ParentNode.RemoveChild (oldmember);
}
- if (!DocUtils.IsDelegate (type) && !ignoremembers) {
+ if (!DocUtils.IsDelegate (type)) {
XmlNode members = WriteElement (basefile.DocumentElement, "Members");
foreach (IMemberReference m in type.GetMembers()) {
if (m is TypeDefinition) continue;
if (sig == null) continue;
if (seenmembers.ContainsKey(sig)) continue;
- // To be nice on diffs, members/properties/events that are overrides or are interface implementations
- // are not added in.
- if (!IsNew(m)) continue;
-
XmlElement mm = MakeMember(basefile, new DocsNodeInfo (null, m));
if (mm == null) continue;
members.AppendChild( mm );
WriteXml(basefile.DocumentElement, writer);
}
- private static string GetCodeSource (string lang, string file)
+ private string GetCodeSource (string lang, string file)
{
int anchorStart;
if (lang == "C#" && (anchorStart = file.IndexOf (".cs#")) >= 0) {
return src.ToString ();
}
} catch (Exception e) {
- Error ("Could not load <code/> file '{0}' region '{1}': {2}",
+ Warning ("Could not load <code/> file '{0}' region '{1}': {2}",
file, region, show_exceptions ? e.ToString () : e.Message);
return null;
}
using (StreamReader reader = new StreamReader (file))
return reader.ReadToEnd ();
} catch (Exception e) {
- Error ("Could not load <code/> file '" + file + "': " + e.Message);
+ Warning ("Could not load <code/> file '" + file + "': " + e.Message);
}
return null;
}
- private static IEnumerable<DocsNodeInfo> GetDocumentationMembers (XmlDocument basefile, TypeDefinition type, XmlReader ecmaDocsMembers)
+ private IEnumerable<DocsNodeInfo> GetDocumentationMembers (XmlDocument basefile, TypeDefinition type, XmlReader ecmaDocsMembers)
{
if (ecmaDocsMembers != null) {
int membersDepth = ecmaDocsMembers.Depth;
if (oldmember == null) {
m = GetMember (type, dm);
if (m == null) {
- Error ("Could not import ECMA docs for `{0}'s `{1}': Member not found.",
+ 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;
else {
m = GetMember (type, new DocumentationMember (oldmember));
if (m == null) {
- Error ("Could not import ECMA docs for `{0}'s `{1}': Member not found.",
+ Warning ("Could not import ECMA docs for `{0}'s `{1}': Member not found.",
type.FullName, dm.MemberSignatures ["C#"]);
continue;
}
}
}
- static void DeleteMember (string reason, string output, XmlNode member, MyXmlNodeList todelete)
+ void DeleteMember (string reason, string output, XmlNode member, MyXmlNodeList todelete)
{
string format = output != null
? "{0}: File='{1}'; Signature='{4}'"
: "{0}: XPath='/Type[@FullName=\"{2}\"]/Members/Member[@MemberName=\"{3}\"]'; Signature='{4}'";
- Error (format,
+ Warning (format,
reason,
output,
member.OwnerDocument.DocumentElement.GetAttribute ("FullName"),
member.Attributes ["MemberName"].Value,
member.SelectSingleNode ("MemberSignature[@Language='C#']/@Value").Value);
if (!delete && MemberDocsHaveUserContent (member)) {
- Error ("Member deletions must be enabled with the --delete option.");
+ Warning ("Member deletions must be enabled with the --delete option.");
} else {
todelete.Add (member);
deletions++;
return false;
}
- private static bool IsNew (IMemberReference m)
- {
- if (!nooverrides) return true;
- if (m is MethodDefinition && !IsNew ((MethodDefinition)m)) return false;
- if (m is PropertyDefinition && !IsNew (((PropertyDefinition)m).GetMethod)) return false;
- if (m is PropertyDefinition && !IsNew (((PropertyDefinition)m).SetMethod)) return false;
- if (m is EventDefinition && !IsNew (((EventDefinition)m).AddMethod)) return false;
- if (m is EventDefinition && !IsNew (((EventDefinition)m).InvokeMethod)) return false;
- if (m is EventDefinition && !IsNew (((EventDefinition)m).RemoveMethod)) return false;
- return true;
- }
-
- private static bool IsNew (MethodDefinition m)
- {
- if (m == null)
- return true;
- return m.IsNewSlot;
- }
-
// UPDATE HELPER FUNCTIONS
private static IMemberReference GetMember (TypeDefinition type, DocumentationMember member)
// CREATE A STUB DOCUMENTATION FILE
- public static XmlElement StubType (TypeDefinition type, string output, XmlReader ecmaDocsType)
+ public XmlElement StubType (TypeDefinition type, string output, XmlReader ecmaDocsType)
{
string typesig = MakeTypeSignature(type);
if (typesig == null) return null; // not publicly visible
return root;
}
- private static XmlElement CreateSinceNode (XmlDocument doc)
+ private XmlElement CreateSinceNode (XmlDocument doc)
{
XmlElement s = doc.CreateElement ("since");
s.SetAttribute ("version", since);
// STUBBING/UPDATING FUNCTIONS
- public static void UpdateType (XmlElement root, TypeDefinition type, XmlReader ecmaDocsType)
+ public void UpdateType (XmlElement root, TypeDefinition type, XmlReader ecmaDocsType)
{
root.SetAttribute("Name", GetDocTypeName (type));
root.SetAttribute("FullName", GetDocTypeFullName (type));
XmlElement ass = WriteElement(root, "AssemblyInfo");
WriteElementText(ass, "AssemblyName", type.Module.Assembly.Name.Name);
- UpdateAssemblyVersions(root, type, true);
+ if (!no_assembly_versions) {
+ UpdateAssemblyVersions (root, 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
return l;
}
- private static void UpdateMember (DocsNodeInfo info)
+ private void UpdateMember (DocsNodeInfo info)
{
XmlElement me = (XmlElement) info.Node;
IMemberReference mi = info.Member;
WriteElementText(me, "MemberType", GetMemberType(mi));
- UpdateAssemblyVersions(me, mi, true);
+ if (!no_assembly_versions) {
+ UpdateAssemblyVersions (me, mi, true);
+ }
+ else {
+ ClearElement (me, "AssemblyInfo");
+ }
ICustomAttributeProvider p = mi as ICustomAttributeProvider;
if (p != null)
MakeAttributes (me, p.CustomAttributes, false);
"typeparam",
};
- private static void UpdateExtensionMethods (XmlElement e, DocsNodeInfo info)
+ private void UpdateExtensionMethods (XmlElement e, DocsNodeInfo info)
{
MethodDefinition me = info.Member as MethodDefinition;
if (me == null)
private static bool GetFieldConstValue (FieldDefinition field, out string value)
{
value = null;
- TypeDefinition type = DocUtils.GetTypeDefinition (field.DeclaringType);
+ TypeDefinition type = field.DeclaringType.Resolve ();
if (type != null && type.IsEnum) return false;
if (type != null && type.IsGenericType ()) return false;
// DOCUMENTATION HELPER FUNCTIONS
- private static void MakeDocNode (DocsNodeInfo info)
+ private void MakeDocNode (DocsNodeInfo info)
{
List<GenericParameter> genericParams = info.GenericParameters;
ParameterDefinitionCollection parameters = info.Parameters;
if (addremarks)
WriteElementInitialText(e, "remarks", "To be added.");
+ if (exceptions.HasValue && info.Member != null) {
+ UpdateExceptions (e, info.Member);
+ }
+
if (info.EcmaDocs != null) {
XmlReader r = info.EcmaDocs;
int depth = r.Depth;
switch (r.Name) {
case "param":
case "typeparam": {
+ string name = r.GetAttribute ("name");
+ if (name == null)
+ break;
XmlNode doc = e.SelectSingleNode (
- r.Name + "[@name='" + r.GetAttribute ("name") + "']");
+ r.Name + "[@name='" + name + "']");
string value = r.ReadInnerXml ();
if (doc != null)
doc.InnerXml = value.Replace ("\r", "");
case "seealso": {
string name = r.Name;
string cref = r.GetAttribute ("cref");
+ if (cref == null)
+ break;
XmlNode doc = e.SelectSingleNode (
r.Name + "[@cref='" + cref + "']");
string value = r.ReadInnerXml ().Replace ("\r", "");
switch (child.Name) {
case "param":
case "typeparam": {
- XmlElement p2 = (XmlElement) e.SelectSingleNode (child.Name + "[@name='" + child.Attributes ["name"].Value + "']");
+ 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;
case "altmember":
case "exception":
case "permission": {
- XmlElement a = (XmlElement) e.SelectSingleNode (child.Name + "[@cref='" + child.Attributes ["cref"].Value + "']");
+ 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", child.Attributes ["cref"].Value);
break;
}
case "seealso": {
- XmlElement a = (XmlElement) e.SelectSingleNode ("altmember[@cref='" + child.Attributes ["cref"].Value + "']");
+ 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", child.Attributes ["cref"].Value);
}
- private static void UpdateParameters (XmlElement e, string element, string[] values)
+ private void UpdateParameters (XmlElement e, string element, string[] values)
{
if (values != null) {
XmlNode[] paramnodes = new XmlNode[values.Length];
string name = paramnode.GetAttribute("name");
if (!seenParams.ContainsKey(name)) {
if (!delete && !paramnode.InnerText.StartsWith("To be added")) {
- Error ("The following param node can only be deleted if the --delete option is given: ");
+ Warning ("The following param node can only be deleted if the --delete option is given: ");
if (e.ParentNode == e.OwnerDocument.DocumentElement) {
// delegate type
- Error ("\tXPath=/Type[@FullName=\"{0}\"]/Docs/param[@name=\"{1}\"]",
+ Warning ("\tXPath=/Type[@FullName=\"{0}\"]/Docs/param[@name=\"{1}\"]",
e.OwnerDocument.DocumentElement.GetAttribute ("FullName"),
name);
}
else {
- Error ("\tXPath=/Type[@FullName=\"{0}\"]//Member[@MemberName=\"{1}\"]/Docs/param[@name=\"{2}\"]",
+ Warning ("\tXPath=/Type[@FullName=\"{0}\"]//Member[@MemberName=\"{1}\"]/Docs/param[@name=\"{2}\"]",
e.OwnerDocument.DocumentElement.GetAttribute ("FullName"),
e.ParentNode.Attributes ["MemberName"].Value,
name);
}
- Error ("\tValue={0}", paramnode.OuterXml);
+ Warning ("\tValue={0}", paramnode.OuterXml);
} else {
todelete.Add (paramnode);
}
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, IMemberReference member)
+ {
+ 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: <see cref=\"" +
+ string.Join ("\" />, <see cref=\"",
+ source.Sources.Select (m => slashdocFormatter.GetDeclaration (m))
+ .ToArray ()) +
+ "\" />";
+ 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.
"System.Runtime.CompilerServices.ExtensionAttribute",
};
- private static void MakeAttributes (XmlElement root, CustomAttributeCollection attributes, bool assemblyAttributes)
+ private void MakeAttributes (XmlElement root, CustomAttributeCollection attributes, bool assemblyAttributes)
{
if (attributes.Count == 0) {
ClearElement(root, "Attributes");
else
e = root.OwnerDocument.CreateElement("Attributes");
- foreach (CustomAttribute attribute in attributes) {
+ foreach (CustomAttribute attribute in attributes.Cast<CustomAttribute> ()
+ .OrderBy (ca => ca.Constructor.DeclaringType.FullName)) {
if (!attribute.Resolve ()) {
// skip?
- Error ("warning: could not resolve type {0}.",
+ Warning ("warning: could not resolve type {0}.",
attribute.Constructor.DeclaringType.FullName);
}
TypeDefinition attrType = attribute.Constructor.DeclaringType as TypeDefinition;
return "\"" + v.ToString () + "\"";
if (v is Boolean)
return (bool)v ? "true" : "false";
- TypeDefinition valueDef = DocUtils.GetTypeDefinition (valueType);
+ TypeDefinition valueDef = valueType.Resolve ();
if (valueDef == null || !valueDef.IsEnum)
return v.ToString ();
string typename = GetDocTypeFullName (valueType);
.ToDictionary (f => Convert.ToUInt64 (f.Constant), f => f.Name);
}
- private static void MakeParameters (XmlElement root, ParameterDefinitionCollection parameters)
+ private void MakeParameters (XmlElement root, ParameterDefinitionCollection parameters)
{
XmlElement e = WriteElement(root, "Parameters");
e.RemoveAll();
}
}
- private static void MakeTypeParameters (XmlElement root, GenericParameterCollection typeParams)
+ private void MakeTypeParameters (XmlElement root, GenericParameterCollection typeParams)
{
if (typeParams == null || typeParams.Count == 0) {
XmlElement f = (XmlElement) root.SelectSingleNode ("TypeParameters");
if ((attrs & GenericParameterAttributes.ReferenceTypeConstraint) != 0)
AppendElementText (ce, "ParameterAttribute", "ReferenceTypeConstraint");
foreach (TypeReference c in constraints) {
- TypeDefinition cd = DocUtils.GetTypeDefinition (c);
+ TypeDefinition cd = c.Resolve ();
AppendElementText (ce,
(cd != null && cd.IsInterface) ? "InterfaceName" : "BaseTypeName",
GetDocTypeFullName (c));
}
}
- private static void MakeParameters (XmlElement root, IMemberReference mi)
+ private void MakeParameters (XmlElement root, IMemberReference mi)
{
if (mi is MethodDefinition && ((MethodDefinition) mi).IsConstructor)
MakeParameters (root, ((MethodDefinition)mi).Parameters);
return GetDocTypeFullName (type).Replace ("@", "&");
}
- private static void MakeReturnValue(XmlElement root, TypeReference type, CustomAttributeCollection attributes)
+ private void MakeReturnValue (XmlElement root, TypeReference type, CustomAttributeCollection attributes)
{
XmlElement e = WriteElement(root, "ReturnValue");
e.RemoveAll();
MakeAttributes(e, attributes, false);
}
- private static void MakeReturnValue (XmlElement root, IMemberReference mi)
+ private void MakeReturnValue (XmlElement root, IMemberReference mi)
{
if (mi is MethodDefinition && ((MethodDefinition) mi).IsConstructor)
return;
throw new ArgumentException(mi + " is a " + mi.GetType().FullName);
}
- private static XmlElement MakeMember(XmlDocument doc, DocsNodeInfo info) {
+ private XmlElement MakeMember(XmlDocument doc, DocsNodeInfo info)
+ {
IMemberReference mi = info.Member;
if (mi is TypeDefinition) return null;
SetMemberInfo (member);
}
- public void SetType (TypeDefinition type)
+ void SetType (TypeDefinition type)
{
if (type == null)
throw new ArgumentNullException ("type");
GenericParameters = new List<GenericParameter> (type.GenericParameters.Cast<GenericParameter> ());
List<TypeReference> declTypes = DocUtils.GetDeclaringTypes (type);
+ int maxGenArgs = DocUtils.GetGenericArgumentCount (type);
for (int i = 0; i < declTypes.Count - 1; ++i) {
- int remove = DocUtils.GetGenericArgumentCount (declTypes [i]);
+ int remove = System.Math.Min (maxGenArgs,
+ DocUtils.GetGenericArgumentCount (declTypes [i]));
+ maxGenArgs -= remove;
while (remove-- > 0)
GenericParameters.RemoveAt (0);
}
SetSlashDocs (type);
}
- public void SetMemberInfo (IMemberReference member)
+ void SetMemberInfo (IMemberReference member)
{
if (member == null)
throw new ArgumentNullException ("member");
public static IMemberReference GetMember (this TypeDefinition type, string member)
{
- return GetMembers (type, member).FirstOrDefault ();
+ 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.Cast<MethodDefinition> ().Where (m => m.Name == method).First ();
+ return type.Methods.Cast<MethodDefinition> ()
+ .Where (m => m.Name == method)
+ .EnsureZeroOrOne ();
}
public static IEnumerable<IMemberReference> GetDefaultMembers (this TypeReference type)
public static TypeDefinition GetType (this AssemblyDefinition assembly, string type)
{
return GetTypes (assembly)
- .Where (td => td.FullName == type)
- .FirstOrDefault ();
+ .Where (td => td.FullName == type)
+ .EnsureZeroOrOne ();
}
public static bool IsGenericType (this TypeReference type)
{
return method.GenericParameters.Count > 0;
}
+
+ public static IMemberReference Resolve (this IMemberReference member)
+ {
+ EventReference er = member as EventReference;
+ if (er != null)
+ return er.Resolve ();
+ FieldReference fr = member as FieldReference;
+ if (fr != null)
+ return fr.Resolve ();
+ MethodReference mr = member as MethodReference;
+ if (mr != null)
+ return mr.Resolve ();
+ PropertyReference pr = member as PropertyReference;
+ if (pr != null)
+ return pr.Resolve ();
+ TypeReference tr = member as TypeReference;
+ if (tr != null)
+ return tr.Resolve ();
+ throw new NotSupportedException ("Cannot find definition for " + member.ToString ());
+ }
}
static class DocUtils {
TypeReference baseRef = type.BaseType;
if (baseRef == null)
return false;
- return baseRef.FullName == "System.Delegate" ||
+ return !type.IsAbstract && baseRef.FullName == "System.Delegate" || // FIXME
baseRef.FullName == "System.MulticastDelegate";
}
: type.GenericParameters.Count;
}
- public static TypeDefinition GetTypeDefinition (TypeReference type)
- {
- // Remove generic instantiation info (so string comparison below works)
- if (type is TypeSpecification)
- type = type.GetOriginalType ();
- TypeDefinition typeDef = type as TypeDefinition;
- if (typeDef == null && type.Module != null) {
- AssemblyNameReference r = type.Module.AssemblyReferences.Cast<AssemblyNameReference> ()
- .Where (anr => anr.Name == type.Scope.Name)
- .FirstOrDefault ();
- if (r != null) {
- AssemblyDefinition ad = type.Module.Assembly.Resolver.Resolve (r);
- if (ad != null) {
- typeDef = ad.GetTypes()
- .Where (t => t.FullName == type.FullName)
- .FirstOrDefault ();
- }
- }
- }
- return typeDef;
- }
-
public static IEnumerable<TypeReference> GetUserImplementedInterfaces (TypeDefinition type)
{
HashSet<string> inheritedInterfaces = GetInheritedInterfaces (type);
List<TypeReference> userInterfaces = new List<TypeReference> ();
foreach (TypeReference iface in type.Interfaces) {
- TypeReference lookup = GetTypeDefinition (iface) ?? iface;
+ TypeReference lookup = iface.Resolve () ?? iface;
if (!inheritedInterfaces.Contains (GetQualifiedTypeName (lookup)))
userInterfaces.Add (iface);
}
if (t == null) return;
foreach (TypeReference r in t.Interfaces) {
inheritedInterfaces.Add (GetQualifiedTypeName (r));
- a (GetTypeDefinition (r));
+ a (r.Resolve ());
}
};
TypeReference baseRef = type.BaseType;
while (baseRef != null) {
- TypeDefinition baseDef = GetTypeDefinition (baseRef);
+ TypeDefinition baseDef = baseRef.Resolve ();
if (baseDef != null) {
a (baseDef);
baseRef = baseDef.BaseType;
baseRef = null;
}
foreach (TypeReference r in type.Interfaces)
- a (GetTypeDefinition (r));
+ a (r.Resolve ());
return inheritedInterfaces;
}
}
}
}
+public enum MemberFormatterState {
+ None,
+ WithinArray,
+ WithinGenericTypeContainer,
+}
+
public abstract class MemberFormatter {
public virtual string GetName (IMemberReference member)
{
TypeReference type = member as TypeReference;
if (type != null)
return GetTypeName (type);
- MethodDefinition method = member as MethodDefinition;
- if (method != null && method.IsConstructor)
+ MethodReference method = member as MethodReference;
+ if (method != null && method.Name == ".ctor") // method.IsConstructor
return GetConstructorName (method);
if (method != null)
return GetMethodName (method);
- PropertyDefinition prop = member as PropertyDefinition;
+ PropertyReference prop = member as PropertyReference;
if (prop != null)
return GetPropertyName (prop);
- FieldDefinition field = member as FieldDefinition;
+ FieldReference field = member as FieldReference;
if (field != null)
return GetFieldName (field);
- EventDefinition e = member as EventDefinition;
+ EventReference e = member as EventReference;
if (e != null)
return GetEventName (e);
throw new NotSupportedException ("Can't handle: " +
get {return new char[]{'[', ']'};}
}
+ protected virtual MemberFormatterState MemberFormatterState { get; set; }
+
protected StringBuilder _AppendTypeName (StringBuilder buf, TypeReference type)
{
if (type is ArrayType) {
TypeSpecification spec = type as TypeSpecification;
_AppendTypeName (buf, spec != null ? spec.ElementType : type.GetOriginalType ())
.Append (ArrayDelimeters [0]);
+ var origState = MemberFormatterState;
+ MemberFormatterState = MemberFormatterState.WithinArray;
ArrayType array = (ArrayType) type;
int rank = array.Rank;
if (rank > 1)
buf.Append (new string (',', rank-1));
+ MemberFormatterState = origState;
return buf.Append (ArrayDelimeters [1]);
}
if (type is ReferenceType) {
int prev = 0;
bool insertNested = false;
foreach (var decl in decls) {
- TypeReference declDef = DocUtils.GetTypeDefinition (decl) ?? decl;
+ TypeReference declDef = decl.Resolve () ?? decl;
if (insertNested) {
buf.Append (NestedTypeSeparator);
}
prev = ac;
if (c > 0) {
buf.Append (GenericTypeContainer [0]);
+ var origState = MemberFormatterState;
+ MemberFormatterState = MemberFormatterState.WithinGenericTypeContainer;
_AppendTypeName (buf, genArgs [argIdx++]);
for (int i = 1; i < c; ++i)
_AppendTypeName (buf.Append (","), genArgs [argIdx++]);
+ MemberFormatterState = origState;
buf.Append (GenericTypeContainer [1]);
}
}
return buf;
}
- protected virtual string GetConstructorName (MethodDefinition constructor)
+ protected virtual string GetConstructorName (MethodReference constructor)
{
return constructor.Name;
}
- protected virtual string GetMethodName (MethodDefinition method)
+ protected virtual string GetMethodName (MethodReference method)
{
return method.Name;
}
- protected virtual string GetPropertyName (PropertyDefinition property)
+ protected virtual string GetPropertyName (PropertyReference property)
{
return property.Name;
}
- protected virtual string GetFieldName (FieldDefinition field)
+ protected virtual string GetFieldName (FieldReference field)
{
return field.Name;
}
- protected virtual string GetEventName (EventDefinition e)
+ protected virtual string GetEventName (EventReference e)
{
return e.Name;
}
public virtual string GetDeclaration (IMemberReference member)
{
+ if (member == null)
+ throw new ArgumentNullException ("member");
TypeDefinition type = member as TypeDefinition;
if (type != null)
return GetTypeDeclaration (type);
protected override StringBuilder AppendTypeName (StringBuilder buf, TypeReference type)
{
if (type is GenericParameter)
- return buf.Append (type.Name);
+ return AppendGenericParameterConstraints (buf, (GenericParameter) type).Append (type.Name);
string t = type.FullName;
if (!t.StartsWith ("System.")) {
return base.AppendTypeName (buf, type);
return base.AppendTypeName (buf, type);
}
+ private StringBuilder AppendGenericParameterConstraints (StringBuilder buf, GenericParameter type)
+ {
+ if (MemberFormatterState != MemberFormatterState.WithinGenericTypeContainer)
+ 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);
ConstraintCollection constraints = genArg.Constraints;
if (attrs == GenericParameterAttributes.NonVariant && constraints.Count == 0)
continue;
- buf.Append (" where ").Append (genArg.Name).Append (" : ");
+
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
modifiers += " override";
}
- if (method.IsAbstract) // TODO && !method.DeclaringType.IsInterface)
+ TypeDefinition declDef = (TypeDefinition) method.DeclaringType;
+ if (method.IsAbstract && !declDef.IsInterface)
modifiers += " abstract";
if (method.IsFinal)
modifiers += " sealed";
private bool AddTypeCount = true;
private TypeReference genDeclType;
- private MethodDefinition genDeclMethod;
+ private MethodReference genDeclMethod;
protected override StringBuilder AppendTypeName (StringBuilder buf, TypeReference type)
{
return base.GetDeclaration (member);
}
- protected override string GetConstructorName (MethodDefinition constructor)
+ protected override string GetConstructorName (MethodReference constructor)
{
return GetMethodDefinitionName (constructor, "#ctor");
}
- protected override string GetMethodName (MethodDefinition method)
+ protected override string GetMethodName (MethodReference method)
{
string name = null;
- if (!DocUtils.IsExplicitlyImplemented (method))
+ MethodDefinition methodDef = method as MethodDefinition;
+ if (methodDef == null || !DocUtils.IsExplicitlyImplemented (methodDef))
name = method.Name;
else {
TypeReference iface;
MethodReference ifaceMethod;
- DocUtils.GetInfoForExplicitlyImplementedMethod (method, out iface, out ifaceMethod);
+ DocUtils.GetInfoForExplicitlyImplementedMethod (methodDef, out iface, out ifaceMethod);
AddTypeCount = false;
name = GetTypeName (iface) + "." + ifaceMethod.Name;
AddTypeCount = true;
return GetMethodDefinitionName (method, name);
}
- private string GetMethodDefinitionName (MethodDefinition method, string name)
+ private string GetMethodDefinitionName (MethodReference method, string name)
{
StringBuilder buf = new StringBuilder ();
buf.Append (GetTypeName (method.DeclaringType));
buf.Append ("``").Append (genArgs.Count);
}
ParameterDefinitionCollection parameters = method.Parameters;
- genDeclType = method.DeclaringType;
- genDeclMethod = method;
- AppendParameters (buf, method.DeclaringType.GenericParameters, parameters);
- genDeclType = null;
- genDeclMethod = null;
+ try {
+ genDeclType = method.DeclaringType;
+ genDeclMethod = method;
+ AppendParameters (buf, method.DeclaringType.GenericParameters, parameters);
+ }
+ finally {
+ genDeclType = null;
+ genDeclMethod = null;
+ }
return buf.ToString ();
}
return buf;
}
- protected override string GetPropertyName (PropertyDefinition property)
+ protected override string GetPropertyName (PropertyReference property)
{
string name = null;
- MethodDefinition method = property.GetMethod;
- if (method == null)
- method = property.SetMethod;
- if (!DocUtils.IsExplicitlyImplemented (method))
+ 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;
return buf.ToString ();
}
- protected override string GetFieldName (FieldDefinition field)
+ protected override string GetFieldName (FieldReference field)
{
return string.Format ("{0}.{1}",
GetName (field.DeclaringType), field.Name);
}
- protected override string GetEventName (EventDefinition e)
+ protected override string GetEventName (EventReference e)
{
return string.Format ("{0}.{1}",
GetName (e.DeclaringType), e.Name);