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:
authorJoel Martinez <joelmartinez@gmail.com>2017-09-28 23:20:38 +0300
committerJoel Martinez <joelmartinez@gmail.com>2017-10-02 23:41:00 +0300
commit8822f7729c04ba22acbe9a9f1141d181ed725b6a (patch)
tree83f3e3c99e6cca9a1080c003e5c273e86eb1be8a /mdoc/Mono.Documentation/Updater
parente7b7f22e6a82a7ec02962b8a18700fe4616839df (diff)
mdoc: reformatting the MDocUpdater source code.
We are changing our coding standards, and starting with the update subcommand. This moves many classes into their own code files and namespaces to better organize the source code.
Diffstat (limited to 'mdoc/Mono.Documentation/Updater')
-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.cs111
-rw-r--r--mdoc/Mono.Documentation/Updater/Frameworks/FrameworkEntry.cs52
-rw-r--r--mdoc/Mono.Documentation/Updater/Frameworks/FrameworkIndex.cs91
-rw-r--r--mdoc/Mono.Documentation/Updater/Frameworks/FrameworkTypeEntry.cs80
-rw-r--r--mdoc/Mono.Documentation/Updater/Frameworks/UwpResolver.cs25
-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
32 files changed, 4077 insertions, 0 deletions
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/Updater/Frameworks/AssemblySet.cs b/mdoc/Mono.Documentation/Updater/Frameworks/AssemblySet.cs
new file mode 100644
index 00000000..524e39a7
--- /dev/null
+++ b/mdoc/Mono.Documentation/Updater/Frameworks/AssemblySet.cs
@@ -0,0 +1,111 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using Mono.Cecil;
+
+namespace Mono.Documentation.Updater.Frameworks
+{
+ /// <summary>
+ /// Represents a set of assemblies that we want to document
+ /// </summary>
+ class AssemblySet : IDisposable
+ {
+ readonly DefaultAssemblyResolver resolver = new Frameworks.UwpResolver ();
+ HashSet<string> assemblyPaths = new HashSet<string> ();
+ HashSet<string> assemblySearchPaths = new HashSet<string> ();
+ HashSet<string> forwardedTypes = new HashSet<string> ();
+ IEnumerable<string> importPaths;
+ public IEnumerable<DocumentationImporter> Importers { get; private set; }
+
+ public AssemblySet (IEnumerable<string> paths) : this ("Default", paths, new string[0], null) { }
+
+ public AssemblySet (string name, IEnumerable<string> paths, IEnumerable<string> resolverSearchPaths, IEnumerable<string> imports)
+ {
+ Name = name;
+
+ foreach (var path in paths)
+ assemblyPaths.Add (path);
+
+ // add default search paths
+ var assemblyDirectories = paths
+ .Where (p => p.Contains (Path.DirectorySeparatorChar))
+ .Select (p => Path.GetDirectoryName (p));
+
+ foreach (var searchPath in resolverSearchPaths.Union (assemblyDirectories))
+ assemblySearchPaths.Add (searchPath);
+
+ char oppositeSeparator = Path.DirectorySeparatorChar == '/' ? '\\' : '/';
+ Func<string, string> sanitize = p =>
+ p.Replace (oppositeSeparator, Path.DirectorySeparatorChar);
+
+ foreach (var searchPath in assemblySearchPaths.Select (sanitize))
+ resolver.AddSearchDirectory (searchPath);
+
+ this.importPaths = imports;
+ if (this.importPaths != null)
+ {
+ this.Importers = this.importPaths.Select (p => MDocUpdater.Instance.GetImporter (p, supportsEcmaDoc: false));
+ }
+ else
+ this.Importers = new DocumentationImporter[0];
+ }
+
+ public string Name { get; private set; }
+
+ public IEnumerable<AssemblyDefinition> Assemblies { get { return this.LoadAllAssemblies ().Where(a => a != null); } }
+ public IEnumerable<string> AssemblyPaths { get { return this.assemblyPaths; } }
+
+ /// <summary>Adds all subdirectories to the search directories for the resolver to look in.</summary>
+ public void RecurseSearchDirectories()
+ {
+ var directories = resolver
+ .GetSearchDirectories ()
+ .Select(d => new DirectoryInfo (d))
+ .Where (d => d.Exists)
+ .Select(d => d.FullName)
+ .ToDictionary(d => d, d => d);
+
+ var subdirs = directories.Keys
+ .SelectMany (d => Directory.GetDirectories (d, ".", SearchOption.AllDirectories))
+ .Where (d => !directories.ContainsKey (d));
+
+ foreach (var dir in subdirs)
+ resolver.AddSearchDirectory (dir);
+ }
+
+ /// <returns><c>true</c>, if in set was contained in the set of assemblies, <c>false</c> otherwise.</returns>
+ /// <param name="name">An assembly file name</param>
+ public bool Contains (string name)
+ {
+ return assemblyPaths.Any (p => Path.GetFileName (p) == name);
+ }
+
+ /// <summary>Tells whether an already enumerated AssemblyDefinition, contains the type.</summary>
+ /// <param name="name">Type name</param>
+ public bool ContainsForwardedType (string name)
+ {
+ return forwardedTypes.Contains (name);
+ }
+
+ public void Dispose () => resolver.Dispose ();
+
+ public override string ToString ()
+ {
+ return string.Format ("[AssemblySet: Name={0}, Assemblies={1}]", Name, assemblyPaths.Count);
+ }
+
+ IEnumerable<AssemblyDefinition> LoadAllAssemblies ()
+ {
+ foreach (var path in this.assemblyPaths) {
+ var assembly = MDocUpdater.Instance.LoadAssembly (path, this.resolver);
+ if (assembly != null) {
+ foreach (var type in assembly.MainModule.ExportedTypes.Where (t => t.IsForwarder).Select (t => t.FullName))
+ forwardedTypes.Add (type);
+ }
+ yield return assembly;
+ }
+ }
+ }
+}
diff --git a/mdoc/Mono.Documentation/Updater/Frameworks/FrameworkEntry.cs b/mdoc/Mono.Documentation/Updater/Frameworks/FrameworkEntry.cs
new file mode 100644
index 00000000..c6684d51
--- /dev/null
+++ b/mdoc/Mono.Documentation/Updater/Frameworks/FrameworkEntry.cs
@@ -0,0 +1,52 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Mono.Cecil;
+using Mono.Cecil.Rocks;
+
+namespace Mono.Documentation.Updater.Frameworks
+{
+ class FrameworkEntry
+ {
+ SortedSet<FrameworkTypeEntry> types = new SortedSet<FrameworkTypeEntry> ();
+
+ List<FrameworkEntry> allframeworks;
+
+ public FrameworkEntry (List<FrameworkEntry> frameworks)
+ {
+ allframeworks = frameworks;
+ if (allframeworks == null)
+ allframeworks = new List<FrameworkEntry> (0);
+ }
+
+ public string Name { get; set; }
+
+ public IEnumerable<DocumentationImporter> Importers { get; set; }
+
+ public ISet<FrameworkTypeEntry> Types { get { return this.types; } }
+
+ public IEnumerable<FrameworkEntry> Frameworks { get { return this.allframeworks; } }
+
+ public static readonly FrameworkEntry Empty = new EmptyFrameworkEntry () { Name = "Empty" };
+
+ public virtual FrameworkTypeEntry ProcessType (TypeDefinition type)
+ {
+
+ var entry = types.FirstOrDefault (t => t.Name.Equals (type.FullName));
+ if (entry == null) {
+ var docid = DocCommentId.GetDocCommentId (type);
+ entry = new FrameworkTypeEntry (this) { Id = docid, Name = type.FullName, Namespace = type.Namespace };
+ types.Add (entry);
+ }
+ return entry;
+ }
+
+ public override string ToString () => this.Name;
+
+ class EmptyFrameworkEntry : FrameworkEntry
+ {
+ public EmptyFrameworkEntry () : base (null) { }
+ public override FrameworkTypeEntry ProcessType (TypeDefinition type) { return FrameworkTypeEntry.Empty; }
+ }
+ }
+}
diff --git a/mdoc/Mono.Documentation/Updater/Frameworks/FrameworkIndex.cs b/mdoc/Mono.Documentation/Updater/Frameworks/FrameworkIndex.cs
new file mode 100644
index 00000000..e392f585
--- /dev/null
+++ b/mdoc/Mono.Documentation/Updater/Frameworks/FrameworkIndex.cs
@@ -0,0 +1,91 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Xml;
+using System.Xml.Linq;
+
+using Mono.Cecil;
+
+namespace Mono.Documentation.Updater.Frameworks
+{
+
+ class FrameworkIndex
+ {
+ List<FrameworkEntry> frameworks = new List<FrameworkEntry> ();
+ string path;
+
+ public FrameworkIndex (string pathToFrameworks)
+ {
+ path = pathToFrameworks;
+ }
+
+ public IList<FrameworkEntry> Frameworks {
+ get {
+ return this.frameworks;
+ }
+ }
+
+ public FrameworkEntry StartProcessingAssembly (AssemblyDefinition assembly, IEnumerable<DocumentationImporter> importers)
+ {
+ if (string.IsNullOrWhiteSpace (this.path))
+ return FrameworkEntry.Empty;
+
+ string assemblyPath = assembly.MainModule.FileName;
+ var frameworksDirectory = this.path.EndsWith ("frameworks.xml", StringComparison.OrdinalIgnoreCase)
+ ? Path.GetDirectoryName (this.path) : this.path;
+ string relativePath = assemblyPath.Replace (frameworksDirectory, string.Empty);
+ string shortPath = Path.GetDirectoryName (relativePath);
+ if (shortPath.StartsWith (Path.DirectorySeparatorChar.ToString (), StringComparison.InvariantCultureIgnoreCase))
+ shortPath = shortPath.Substring (1, shortPath.Length - 1);
+
+
+ var entry = frameworks.FirstOrDefault (f => f.Name.Equals (shortPath));
+ if (entry == null) {
+ entry = new FrameworkEntry (frameworks) { Name = shortPath, Importers = importers };
+ frameworks.Add (entry);
+ }
+ return entry;
+ }
+
+ /// <summary>Writes the framework indices to disk.</summary>
+ /// <param name="path">The folder where one file for every FrameworkEntry will be written.</param>
+ public void WriteToDisk (string path)
+ {
+ if (string.IsNullOrWhiteSpace (this.path))
+ return;
+
+ string outputPath = Path.Combine (path, "FrameworksIndex");
+ if (!Directory.Exists (outputPath))
+ Directory.CreateDirectory (outputPath);
+
+ foreach (var fx in this.frameworks) {
+
+ XDocument doc = new XDocument (
+ new XElement("Framework",
+ new XAttribute ("Name", fx.Name),
+ fx.Types
+ .GroupBy(t => t.Namespace)
+ .Select(g => new XElement("Namespace",
+ new XAttribute("Name", g.Key),
+ g.Select (t => new XElement ("Type",
+ new XAttribute ("Name", t.Name),
+ new XAttribute("Id", t.Id),
+ t.Members.Select (m =>
+ new XElement ("Member",
+ new XAttribute ("Id", m)))))))));
+
+ // now save the document
+ string filePath = Path.Combine (outputPath, fx.Name + ".xml");
+
+ if (File.Exists (filePath))
+ File.Delete (filePath);
+
+ var settings = new XmlWriterSettings { Indent = true };
+ using (var writer = XmlWriter.Create (filePath, settings)) {
+ doc.WriteTo (writer);
+ }
+ }
+ }
+ }
+}
diff --git a/mdoc/Mono.Documentation/Updater/Frameworks/FrameworkTypeEntry.cs b/mdoc/Mono.Documentation/Updater/Frameworks/FrameworkTypeEntry.cs
new file mode 100644
index 00000000..67bcee86
--- /dev/null
+++ b/mdoc/Mono.Documentation/Updater/Frameworks/FrameworkTypeEntry.cs
@@ -0,0 +1,80 @@
+using System;
+using System.Collections.Generic;
+using Mono.Cecil;
+using Mono.Cecil.Rocks;
+
+namespace Mono.Documentation.Updater.Frameworks
+{
+ class FrameworkTypeEntry : IComparable<FrameworkTypeEntry>
+ {
+ SortedSet<string> members = new SortedSet<string> ();
+ SortedSet<string> memberscsharpsig = new SortedSet<string> ();
+
+ ILFullMemberFormatter formatter = new ILFullMemberFormatter ();
+
+ FrameworkEntry fx;
+
+ public static FrameworkTypeEntry Empty = new EmptyTypeEntry (FrameworkEntry.Empty) { Name = "Empty" };
+
+ public FrameworkTypeEntry (FrameworkEntry fx)
+ {
+ this.fx = fx;
+ }
+
+ public string Id { get; set; }
+ public string Name { get; set; }
+ public string Namespace { get; set; }
+ public FrameworkEntry Framework { get { return fx; } }
+
+ public ISet<string> Members {
+ get {
+ return this.members;
+ }
+ }
+
+ public virtual void ProcessMember (MemberReference member)
+ {
+ var resolvedMember = member.Resolve ();
+ if (resolvedMember != null) {
+ var docid = DocCommentId.GetDocCommentId (resolvedMember);
+ members.Add (docid);
+ }
+ else
+ members.Add (member.FullName);
+
+ // this is for lookup purposes
+ try {
+ memberscsharpsig.Add(formatter.GetDeclaration(member));
+ }
+ catch {}
+ }
+
+ public bool ContainsCSharpSig (string sig)
+ {
+ return memberscsharpsig.Contains (sig);
+ }
+
+ public override string ToString () => $"{this.Name} in {this.fx.Name}";
+
+ public int CompareTo (FrameworkTypeEntry other)
+ {
+ if (other == null) return -1;
+ if (this.Name == null) return 1;
+
+ return string.Compare (this.Name, other.Name, StringComparison.CurrentCulture);
+ }
+
+ public override bool Equals (object obj)
+ {
+ FrameworkTypeEntry other = obj as FrameworkTypeEntry;
+ if (other == null) return false;
+ return this.Name.Equals (other.Name);
+ }
+
+ class EmptyTypeEntry : FrameworkTypeEntry
+ {
+ public EmptyTypeEntry (FrameworkEntry fx) : base (fx) { }
+ public override void ProcessMember (MemberReference member) { }
+ }
+ }
+}
diff --git a/mdoc/Mono.Documentation/Updater/Frameworks/UwpResolver.cs b/mdoc/Mono.Documentation/Updater/Frameworks/UwpResolver.cs
new file mode 100644
index 00000000..4dbbec82
--- /dev/null
+++ b/mdoc/Mono.Documentation/Updater/Frameworks/UwpResolver.cs
@@ -0,0 +1,25 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using Microsoft.Win32;
+using Mono.Cecil;
+
+namespace Mono.Documentation.Updater.Frameworks
+{
+ /// <summary>Mono.Cecil resolver for the windows universal platform</summary>
+ class UwpResolver : DefaultAssemblyResolver
+ {
+ public override AssemblyDefinition Resolve (AssemblyNameReference name)
+ {
+ var ver = name.Version;
+ if (ver.Major == 255 && ver.Minor == 255 && ver.Revision == 255 && name.Name == "mscorlib")
+ {
+ var v = new Version (4, 5, 0);
+ var anr = new AssemblyNameReference (name.Name, v);
+ return base.Resolve (anr);
+ }
+ else
+ return base.Resolve (name);
+ }
+ }
+} \ No newline at end of file
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