Imported Upstream version 6.6.0.89

Former-commit-id: b39a328747c2f3414dc52e009fb6f0aa80ca2492
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2019-09-24 08:53:40 +00:00
parent cf815e07e0
commit 95fdb59ea6
2556 changed files with 138145 additions and 47453 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,105 @@
using System;
using System.Collections.Generic;
using System.Xml;
using Mono.Cecil;
using Mono.Documentation.Util;
namespace Mono.Documentation.Updater
{
public 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");
}
}
}

View File

@@ -0,0 +1,426 @@
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;
using Mono.Documentation.Updater.Frameworks;
namespace Mono.Documentation.Updater
{
public 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;
}
}
public virtual IEnumerable<DocsNodeInfo> GetDocumentationMembers (XmlDocument basefile, TypeDefinition type, FrameworkTypeEntry typeEntry)
{
foreach (XmlElement oldmember in basefile.SelectNodes ("Type/Members/Member"))
{
if (oldmember.GetAttribute ("__monodocer-seen__") == "true")
{
oldmember.RemoveAttribute ("__monodocer-seen__");
continue;
}
if (oldmember.ParentNode == null)
continue;
MemberReference m = GetMember (type, new DocumentationMember (oldmember, typeEntry));
if (m == null)
{
yield return new DocsNodeInfo (oldmember);
}
else
{
yield return new DocsNodeInfo (oldmember, m);
}
}
}
public 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, membertype).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++)
{
bool isRefType = pis[i].ParameterType is ByReferenceType;
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];
bool xmlIsRefType = xmlMemberType.Contains ('&');
bool refTypesMatch = isRefType == xmlIsRefType;
if (!refTypesMatch) {
good = false;
break;
}
xmlMemberType = xmlIsRefType ? xmlMemberType.Substring (0, xmlMemberType.Length - 1) : xmlMemberType;
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;
}
public static IEnumerable<MemberReference> GetReflectionMembers (TypeDefinition type, string docName, string memberType)
{
return GetReflectionMembersCore (type, docName, memberType)
.Distinct ();
}
private static IEnumerable<MemberReference> GetReflectionMembersCore (TypeDefinition type, string docName, string memberType)
{
// 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)
{
int memberCount = 0;
// Cases 1 & 2
foreach (MemberReference mi in type.GetMembers (docName))
{
memberCount++;
yield return mi;
}
if (memberCount == 0 && 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));
};
// 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))
{
memberCount++;
yield return mi;
}
}
if (memberCount == 0 && memberType == "Property")
{
foreach (MemberReference mr in type.GetMembers().Where(x => x is PropertyDefinition))
{
var method = ((PropertyDefinition) mr).GetMethod ?? ((PropertyDefinition) mr).SetMethod;
if (method?.Overrides != null && method.Overrides.Any())
{
DocUtils.GetInfoForExplicitlyImplementedMethod(method, out var iface, out var ifaceMethod);
var newName = DocUtils.GetMemberForProperty(ifaceMethod.Name);
if (newName == memberName && verifyInterface(mr) && docName.Contains (iface.Name))
yield return mr;
}
}
}
}
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;
}
}
}

View File

@@ -0,0 +1,8 @@
namespace Mono.Documentation.Updater
{
public abstract class DocumentationImporter
{
public abstract void ImportDocumentation (DocsNodeInfo info);
}
}

View File

@@ -0,0 +1,201 @@
using System;
using System.Xml;
using System.Linq;
using StringList = System.Collections.Generic.List<string>;
using StringToStringMap = System.Collections.Generic.Dictionary<string, string>;
using Mono.Documentation.Updater.Frameworks;
namespace Mono.Documentation.Updater
{
public 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) { }
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)
{
var ptype = reader.GetAttribute ("Type");
var reftypeAttribute = reader.GetAttribute ("RefType");
if (!ptype.EndsWith("&", StringComparison.Ordinal) &&
(reftypeAttribute == "out" || reftypeAttribute == "ref"))
{
// let's add the `&` back, for comparisons
ptype += '&';
}
p.Add (ptype);
}
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, FrameworkTypeEntry typeEntry)
{
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;
var p = node.SelectNodes ("Parameters/Parameter[not(@apistyle) or @apistyle='classic']").Cast<XmlElement>().ToArray ();
if (p.Length > 0)
{
Func<string, string, string> processType = (reftype, typename) =>
!typename.EndsWith("&", StringComparison.Ordinal) && (reftype == "ref" || reftype == "out") ? typename + '&' : typename;
if (p.Any (para => para.HasAttribute ("Index")))
{
var pgroup = p
.Select (para => new
{
Index = para.GetAttribute ("Index"),
Type = para.GetAttribute ("Type"),
RefType = para.GetAttribute ("RefType")
})
.GroupBy (para => new
{
para.Index,
Type = processType (para.RefType, para.Type)
})
.ToArray ();
Parameters = new StringList (pgroup.Length);
Parameters.AddRange (pgroup.Select (pg => pg.Key.Type));
}
else {
var ptypes = p
.Select (para => new
{
Type = para.GetAttribute ("Type"),
RefType = para.GetAttribute ("RefType")
})
.Select (para => processType(para.RefType, para.Type))
.ToArray ();
Parameters = new StringList (ptypes);
}
}
XmlNodeList tp = node.SelectNodes ("TypeParameters/TypeParameter[not(@apistyle) or @apistyle='classic']");
if (tp.Count > 0)
{
TypeParameters = new StringList (tp.Count);
for (int i = 0; i < tp.Count; ++i)
TypeParameters.Add (tp[i].Attributes["Name"].Value);
}
else
{
DiscernTypeParameters ();
}
CleanTypes ();
}
void DiscernTypeParameters ()
{
// see if we can discern the param list from the name
if (MemberName.Contains ("<") && MemberName.EndsWith (">"))
{
var starti = MemberName.IndexOf ("<") + 1;
var endi = MemberName.LastIndexOf (">");
var paramlist = MemberName.Substring (starti, endi - starti);
var tparams = paramlist.Split (new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
TypeParameters = new StringList (tparams);
}
}
public override string ToString ()
{
if (MemberSignatures.Count > 0)
return MemberSignatures.Values.First ();
else
return $"{MemberType}{ReturnType} {MemberName}<{TypeParameters.Count}> ({Parameters.Count})";
}
}
}

View File

@@ -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.SafeCast<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 ());
}
}
}
}

View File

@@ -0,0 +1,169 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml;
using Mono.Cecil;
using Mono.Documentation.Updater.Frameworks;
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, FrameworkTypeEntry typeEntry)
{
return GetMembers (basefile, type, typeEntry)
.Concat (base.GetDocumentationMembers (basefile, type, typeEntry));
}
private IEnumerable<DocsNodeInfo> GetMembers (XmlDocument basefile, TypeDefinition type, FrameworkTypeEntry typeEntry)
{
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)); //todo: why always null???
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, typeEntry));
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;
}
}
}
}
}

View File

@@ -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;
}
}
}
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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 = "\"" + MDocUpdater.FilterSpecialChars (v.ToString ()) + "\"";
return true;
}
if (valueType.FullName == "System.Char")
{
returnvalue = "'" + MDocUpdater.FilterSpecialChars (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;
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -0,0 +1,13 @@
using System.Text;
using Mono.Cecil;
namespace Mono.Documentation.Updater.Formatters.CppFormatters
{
public class CppCxMemberFormatter : CppCxFullMemberFormatter
{
protected override StringBuilder AppendNamespace (StringBuilder buf, TypeReference type)
{
return buf;
}
}
}

View File

@@ -0,0 +1,14 @@
using System.Text;
using Mono.Cecil;
using Mono.Documentation.Updater.CppFormatters;
namespace Mono.Documentation.Updater.Formatters.CppFormatters
{
public class CppMemberFormatter : CppFullMemberFormatter
{
protected override StringBuilder AppendNamespace (StringBuilder buf, TypeReference type)
{
return buf;
}
}
}

View File

@@ -0,0 +1,348 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Mono.Cecil;
using Mono.Documentation.Updater.Formatters.CppFormatters;
namespace Mono.Documentation.Updater.CppFormatters
{
public class CppWinRtFullMemberFormatter : CppCxFullMemberFormatter
{
protected override bool AppendHatOnReturn => false;
protected override string HatModifier => $" const{RefTypeModifier}";
public override string Language => Consts.CppWinRt;
protected override string RefTypeModifier => " &";
protected override IList<string> GetAllowedTypes()
{
return new List<string>(AllowedFundamentalTypes);
}
protected override StringBuilder AppendNamespace(StringBuilder buf, TypeReference type)
{
var @namespace=base.AppendNamespace(buf, type);
if (@namespace.ToString().StartsWith($"Windows{NestedTypeSeparator}"))
{
buf.Insert(0, $"winrt{NestedTypeSeparator}");
}
return @namespace;
}
protected override string GetCppType(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];
foreach (var str in splitType)
{
if (str == "modopt(System.Runtime.CompilerServices.IsLong)" && typeToCompare == "System.Int32")
return "long";
if (str == "modopt(System.Runtime.CompilerServices.IsSignUnspecifiedByte)" &&
typeToCompare == "System.SByte")
return "char";
}
}
switch (typeToCompare)
{
case "System.Byte": typeToCompare = "byte"; break;
case "System.Int16": typeToCompare = "short"; break;
case "System.Int32": typeToCompare = "int"; break;
case "System.Int64": typeToCompare = "long"; break;
case "System.UInt16": typeToCompare = "unsigned short"; break;
case "System.UInt32": typeToCompare = "unsigned int"; break;
case "System.UInt64": typeToCompare = "unsigned long";break;
case "System.Single": typeToCompare = "float"; break;
case "System.Double": typeToCompare = "double"; break;
case "System.Boolean": typeToCompare = "bool"; break;
case "System.Char": typeToCompare = "char"; break;
case "System.Void": typeToCompare = "void"; break;
//API specific type is "winrt::hstring"; but c++ in built type is better variant
case "System.String": typeToCompare = "std::wstring"; break;
case "System.Object": typeToCompare = "winrt::Windows::Foundation::IInspectable"; 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 AppendParameter(StringBuilder buf, ParameterDefinition parameter)
{
if (parameter.ParameterType is ByReferenceType && parameter.IsOut)
{
//no notion of out -> mark with attribute to distinguish in other languages
buf.Append("[Runtime::InteropServices::Out] ");
}
if (parameter.HasCustomAttributes)
{
var isParams = parameter.CustomAttributes.Any(ca => ca.AttributeType.Name == "ParamArrayAttribute");
if (isParams)
buf.AppendFormat("... ");
}
buf.Append(GetTypeNameWithOptions(parameter.ParameterType, !AppendHatOnReturn)).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 GetTypeKind(TypeDefinition t)
{
if (t.IsEnum || t.FullName == "System.Enum")
return "enum";
if (t.IsValueType)
return "struct";
if (t.IsClass)
return "class";
if (t.IsInterface)
return "__interface";
throw new ArgumentException(t.FullName);
}
protected override StringBuilder AppendArrayTypeName(StringBuilder buf, TypeReference type,
DynamicParserContext context)
{
buf.Append("std::Array <");
var item = type is TypeSpecification spec ? spec.ElementType : type.GetElementType();
_AppendTypeName(buf, item, context);
AppendHat(buf, item);
if (type is ArrayType arrayType)
{
int rank = arrayType.Rank;
if (rank > 1)
{
buf.AppendFormat(", {0}", rank);
}
}
buf.Append(">");
return buf;
}
protected override StringBuilder AppendExplisitImplementationMethod(StringBuilder buf, MethodDefinition method)
{
//no need to add additional syntax
return buf;
}
protected override string GetTypeDeclaration(TypeDefinition type)
{
StringBuilder buf = new StringBuilder();
var genericParamList = GetTypeSpecifiGenericParameters(type);
AppendGenericItem(buf, genericParamList);
AppendGenericTypeConstraints(buf, type);
AppendWebHostHiddenAttribute(buf, type);
buf.Append(GetTypeKind(type));
buf.Append(" ");
buf.Append(GetCppType(type.FullName) == null
? GetNameWithOptions(type, false, false)
: type.Name);
if (type.IsAbstract && !type.IsInterface)
buf.Append(" abstract");
if (type.IsSealed && !DocUtils.IsDelegate(type) && !type.IsValueType)
buf.Append(" sealed");
CppWinRtFullMemberFormatter full = new CppWinRtFullMemberFormatter();
if (!type.IsEnum)
{
TypeReference basetype = type.BaseType;
if (basetype != null && basetype.FullName == "System.Object" || type.IsValueType) // FIXME
basetype = null;
List<string> interfaceNames;
try
{
//for winRt Resolve() can fail as Cecil understands winRt types as .net (eg, "System.Object" cannot be resolved)
interfaceNames = DocUtils.GetUserImplementedInterfaces(type)
.Select(iface => full.GetNameWithOptions(iface, true, false))
.OrderBy(s => s)
.ToList();
}
catch
{
interfaceNames = null;
}
if (basetype != null || interfaceNames?.Count > 0)
buf.Append(" : ");
if (basetype != null)
{
buf.Append(full.GetNameWithOptions(basetype, true, false));
if (interfaceNames?.Count > 0)
buf.Append(", ");
}
for (int i = 0; i < interfaceNames?.Count; i++)
{
if (i != 0)
buf.Append(", ");
buf.Append(interfaceNames?[i]);
}
}
return buf.ToString();
}
protected override string GetTypeVisibility(TypeAttributes ta)
{
//Cannot have pubic/protected visibility since it uses native C++ which cannot be exposed
return string.Empty;
}
protected override StringBuilder AppendVisibility(StringBuilder buf, MethodDefinition method)
{
//Cannot have pubic/protected visibility since it uses native C++ which cannot be exposed
return buf;
}
protected override StringBuilder AppendFieldVisibility(StringBuilder buf, FieldDefinition field)
{
//Cannot have pubic/protected visibility since it uses native C++ which cannot be exposed
return buf;
}
protected override StringBuilder AppendGenericItem(StringBuilder buf, IList<GenericParameter> args)
{
if (args != null && args.Any())
{
buf.Append("template <typename ");
buf.Append(args[0].Name);
for (int i = 1; i < args.Count; ++i)
buf.Append(", typename ").Append(args[i].Name);
buf.Append(">");
buf.Append(GetLineEnding());
}
return buf;
}
protected override string AppendSealedModifiers(string modifiersString, MethodDefinition method)
{
if (method.IsFinal) modifiersString += " sealed";
if (modifiersString == " virtual sealed") modifiersString = "";
return modifiersString;
}
public override bool IsSupported(TypeReference tref)
{
if (HasNestedClassesDuplicateNames(tref))
return false;
var ns = DocUtils.GetNamespace(tref);
var allowedTypes = GetAllowedTypes();
if (allowedTypes.Contains(tref.FullName.Split(' ')[0])
//winRt specific namespaces so no need for further check
|| ns.StartsWith("Windows.")
)
{
return true;
}
TypeDefinition typedef = null;
try
{
typedef = tref.Resolve();
}
catch
{
//for winRt Resolve() can fail as Cecil understands winRt types as .net (eg, "System.Object" cannot be resolved)
}
if (typedef != null)
{
if(allowedTypes.Contains(typedef.FullName))
//to check type of array
return true;
if (DocUtils.IsDelegate(typedef))
{
//delegates can be used only in managed context
return false;
}
if (typedef.HasGenericParameters &&
typedef.GenericParameters.Any(x => x.HasConstraints
|| x.HasReferenceTypeConstraint
|| x.HasDefaultConstructorConstraint
|| x.HasNotNullableValueTypeConstraint)
)
{
//Type parameters cannot be constrained
return false;
}
if (HasUnsupportedParent(typedef))
{
return false;
}
}
return IsSupportedGenericParameter(tref)
&& !ns.StartsWith("System.") && !ns.Equals("System");
}
public override bool IsSupportedProperty(PropertyDefinition pdef)
{
//properties can be used only in managed context
return false;
}
public override bool IsSupportedEvent(EventDefinition edef)
{
//events can be used only in managed context
return false;
}
public override bool IsSupportedField(FieldDefinition fdef)
{
return IsSupported(fdef.FieldType);
}
public override bool IsSupportedMethod(MethodDefinition mdef)
{
if (DocUtils.IsExtensionMethod(mdef)
//no support of 'params';
//can be substituted with 'Variadic functions' hovewer it's not full equivalent(not type safe + specific mechanism for reading)
|| mdef.Parameters.Any(IsParamsParameter)
)
{
return false;
}
return
IsSupported(mdef.ReturnType)
&& mdef.Parameters.All(i => IsSupported(i.ParameterType));
}
}
}

View File

@@ -0,0 +1,14 @@
using System.Text;
using Mono.Cecil;
using Mono.Documentation.Updater.CppFormatters;
namespace Mono.Documentation.Updater.Formatters.CppFormatters
{
public class CppWinRtMemberFormatter : CppWinRtFullMemberFormatter
{
protected override StringBuilder AppendNamespace(StringBuilder buf, TypeReference type)
{
return buf;
}
}
}

View File

@@ -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) + ") " + MDocUpdater.FilterSpecialChars(v.ToString ());
return true;
}
}
}

Some files were not shown because too many files have changed in this diff Show More