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

View File

@@ -3,5 +3,8 @@
/Test/DocTest.*
/Test/*.dll*
/Test/FrameworkTestData*
/Test/fx-import
Test/DocTest-DropNS-classic.xml
/.v2.txt
/.v0.txt
/.v0.txt
/Test/test-nuget-information

View File

@@ -3,6 +3,35 @@ namespace Mono.Documentation
{
public static class Consts
{
public static string MonoVersion = "5.0.0.14";
}
public static string MonoVersion = "5.7.4.9";
public const string DocId = "DocId";
public const string CppCli = "C++ CLI";
public const string CppCx = "C++ CX";
public const string CppWinRt = "C++ WINRT";
public const string VbNet = "VB.NET";
public const string DocIdLowCase = "docid";
public const string VbNetLowCase = "vb.net";
public const string CppCliLowCase = "c++/cli";
public const string CppCxLowCase = "c++/cx";
public const string CppWinRtLowCase = "c++/winrt";
public const string Tab = " ";
public const string FSharp = "F#";
public const string FSharpLowCase = "f#";
public const string Javascript = "JavaScript";
public const string JavascriptLowCase = "javascript";
public const string DependencyPropertyFullName = "System.Windows.DependencyProperty";
public const string DependencyPropertyFullNameXaml = "Windows.UI.Xaml.DependencyProperty";
public const string DependencyObjectFullName = "System.Windows.DependencyObject";
public const string DependencyObjectFullNameXaml = "Windows.UI.Xaml.DependencyObject";
public const string VoidFullName = "System.Void";
public const string RefTypeObsoleteString = "Types with embedded references are not supported in this version of your compiler.";
public const string FrameworksIndexFolderName = "FrameworksIndex";
public const string CompilerGeneratedAttribute = "System.Runtime.CompilerServices.CompilerGeneratedAttribute";
public const string CompilationMappingAttribute = "Microsoft.FSharp.Core.CompilationMappingAttribute";
public const string FrameworksIndex = "FrameworksIndex";
public const string FrameworkAlternate = "FrameworkAlternate";
public const string Index = "Index";
}
}

View File

@@ -0,0 +1,8 @@

// This file is used by Code Analysis to maintain SuppressMessage
// attributes that are applied to this project.
// Project-level suppressions either have no target or are given
// a specific target and scoped to a namespace, type, member, etc.
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage ("Potential Code Quality Issues", "RECS0022:A catch clause that catches System.Exception and has an empty body", Justification = "<Pending>", Scope = "member", Target = "~M:Mono.Documentation.Updater.Frameworks.FrameworkTypeEntry.ProcessMember(Mono.Cecil.MemberReference)")]

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,71 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Xml;
using System.Xml.Linq;
namespace Mono.Documentation.Framework
{
public static class FrameworkIndexHelper
{
public static Dictionary<string, FrameworkNamespaceModel> CreateFrameworkIndex(string path, string frameworkName)
{
string frameworkFilePath = GetFrameworkFilePath(path, frameworkName);
if (!File.Exists(frameworkFilePath))
{
throw new ArgumentException($"Can't find framework file: {frameworkFilePath}");
}
using (XmlReader xmlReader = XmlReader.Create(frameworkFilePath))
{
return ReadFrameworkIndex(xmlReader);
}
}
public static Dictionary<string, FrameworkNamespaceModel> ReadFrameworkIndex(XmlReader xmlReader)
{
var dict = new Dictionary<string, FrameworkNamespaceModel>();
xmlReader.ReadToFollowing("Framework");
xmlReader.ReadToDescendant("Namespace");
while (xmlReader.NodeType != XmlNodeType.EndElement)
{
XNode node = XNode.ReadFrom(xmlReader);
XElement element = node as XElement;
if (element == null) continue;
var ns = new FrameworkNamespaceModel(node);
dict.Add(ns.Name, ns);
}
return dict;
}
private static string GetFrameworkFilePath(string path, string frameworkName)
{
string docsRoot = Path.GetDirectoryName(path) ?? "";
string frameworksIndexPath = Path.Combine(docsRoot, Consts.FrameworksIndexFolderName);
foreach (string frameworkIndexFilePath in Directory.EnumerateFiles(frameworksIndexPath))
{
using (XmlReader xmlReader = XmlReader.Create(frameworkIndexFilePath))
{
bool isFrameworkNodeFound = xmlReader.ReadToFollowing("Framework");
if (!isFrameworkNodeFound)
{
throw new InvalidOperationException($"Invalid framework file format in {frameworkIndexFilePath}");
}
var frameworkNameInFile = xmlReader.GetAttribute("Name");
if (frameworkNameInFile == frameworkName)
{
return frameworkIndexFilePath;
}
}
}
throw new InvalidEnumArgumentException($"Can't find file for frameworkName = {frameworkName}");
}
}
}

View File

@@ -0,0 +1,23 @@
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
namespace Mono.Documentation.Framework
{
public class FrameworkNamespaceModel
{
public string Name { get; }
public List<FrameworkTypeModel> Types { get; } = new List<FrameworkTypeModel>();
public FrameworkNamespaceModel(XNode node)
{
var element = node as XElement;
Name = element.Attributes(XName.Get("Name")).First().Value;
var children = element.Elements();
foreach (XElement rawType in children)
{
Types.Add(new FrameworkTypeModel(rawType));
}
}
}
}

View File

@@ -0,0 +1,25 @@
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
namespace Mono.Documentation.Framework
{
public class FrameworkTypeModel
{
public string Name { get; }
public string Id { get; }
public List<string> Members { get; } = new List<string>();
public FrameworkTypeModel(XElement element)
{
Name = element.Attributes(XName.Get("Name")).First().Value;
Id = element.Attributes(XName.Get("Id")).First().Value;
var children = element.Elements();
foreach (XElement rawMember in children)
{
Members.Add(rawMember.Attributes(XName.Get("Id")).First().Value);
}
}
}
}

View File

@@ -1,85 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Mono.Cecil;
namespace Mono.Documentation
{
/// <summary>
/// Represents a set of assemblies that we want to document
/// </summary>
class AssemblySet : IDisposable
{
readonly DefaultAssemblyResolver resolver = new DefaultAssemblyResolver ();
HashSet<string> assemblyPaths = new HashSet<string> ();
HashSet<string> assemblySearchPaths = new HashSet<string> ();
HashSet<string> forwardedTypes = new HashSet<string> ();
public AssemblySet (string path) : this (new string[] { path }) { }
public AssemblySet (IEnumerable<string> paths) : this ("Default", paths, new string[0]) { }
public AssemblySet (string name, IEnumerable<string> paths, IEnumerable<string> resolverSearchPaths)
{
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);
}
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; } }
/// <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;
}
}
}
}

View File

@@ -1,50 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Mono.Cecil;
using Mono.Cecil.Rocks;
namespace Mono.Documentation
{
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 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; }
}
}
}

View File

@@ -1,89 +0,0 @@
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
{
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)
{
if (string.IsNullOrWhiteSpace (this.path))
return FrameworkEntry.Empty;
string assemblyPath = assembly.MainModule.FileName;
string relativePath = assemblyPath.Replace (this.path, 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 };
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);
}
}
}
}
}

View File

@@ -1,80 +0,0 @@
using System;
using System.Collections.Generic;
using Mono.Cecil;
using Mono.Cecil.Rocks;
namespace Mono.Documentation
{
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) { }
}
}
}

View File

@@ -0,0 +1,46 @@
using System;
using System.Runtime.Serialization;
namespace Mono.Documentation
{
[Serializable]
internal class MDocException : Exception
{
public MDocException()
{
}
public MDocException(string message) : base(message)
{
}
public MDocException(string message, Exception innerException) : base(message, innerException)
{
}
protected MDocException(SerializationInfo info, StreamingContext context) : base(info, context)
{
}
}
[Serializable]
internal class MDocAssemblyException : Exception
{
public string AssemblyName { get; set; }
public MDocAssemblyException(string assemblyName, string message) : base(message)
{
this.AssemblyName = assemblyName;
}
public MDocAssemblyException(string assemblyName, string message, Exception innerException) : base(message, innerException)
{
this.AssemblyName = assemblyName;
}
protected MDocAssemblyException(string assemblyName, SerializationInfo info, StreamingContext context) : base(info, context)
{
this.AssemblyName = assemblyName;
}
}
}

View File

@@ -0,0 +1 @@
31df07b0ecd44b6f17de5743fa17e8c2bb96fe78

View File

@@ -0,0 +1,156 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Xml;
using System.Xml.Schema;
using Mono.Options;
namespace Mono.Documentation
{
public class MDocValidator : MDocCommand
{
XmlReaderSettings settings;
long errors = 0;
public override void Run (IEnumerable<string> args)
{
string[] validFormats = {
"ecma",
};
string format = "ecma";
var p = new OptionSet () {
{ "f|format=",
"The documentation {0:FORMAT} used within PATHS. " +
"Valid formats include:\n " +
string.Join ("\n ", validFormats) + "\n" +
"If no format provided, `ecma' is used.",
v => format = v },
};
List<string> files = Parse (p, args, "validate",
"[OPTIONS]+ PATHS",
"Validate PATHS against the specified format schema.");
if (files == null)
return;
if (Array.IndexOf (validFormats, format) < 0)
Error ("Invalid documentation format: {0}.", format);
Run (format, files);
}
public void Run (string format, IEnumerable<string> files)
{
InitializeSchema (format);
// skip args[0] because it is the provider name
foreach (string arg in files)
{
if (IsMonodocFile (arg))
ValidateFile (arg);
if (Directory.Exists (arg))
{
RecurseDirectory (arg);
}
}
Message (errors == 0 ? TraceLevel.Info : TraceLevel.Error,
"Total validation errors: {0}", errors);
}
public void InitializeSchema (string format, ValidationEventHandler extraHandler = null)
{
Stream s = null;
switch (format)
{
case "ecma":
s = Assembly.GetExecutingAssembly ().GetManifestResourceStream ("monodoc-ecma.xsd");
break;
default:
throw new NotSupportedException (string.Format ("The format `{0}' is not suppoted.", format));
}
if (s == null)
throw new NotSupportedException (string.Format ("The schema for `{0}' was not found.", format));
settings = new XmlReaderSettings ();
settings.Schemas.Add (XmlSchema.Read (s, null));
settings.Schemas.Compile ();
settings.ValidationType = ValidationType.Schema;
settings.ValidationEventHandler += OnValidationEvent;
if (extraHandler != null)
settings.ValidationEventHandler += extraHandler;
}
public void ValidateFile (string file)
{
if (settings == null) InitializeSchema ("ecma");
try
{
using (var reader = XmlReader.Create (new XmlTextReader (file), settings))
{
while (reader.Read ())
{
// do nothing
}
}
}
catch (Exception e)
{
Message (TraceLevel.Error, "mdoc: {0}", e.ToString ());
}
}
public void ValidateFile (TextReader textReader)
{
if (settings == null) InitializeSchema ("ecma");
try
{
using (var xmlReader = XmlReader.Create (textReader, settings))
while (xmlReader.Read ()) {}
}
catch (Exception e)
{
Message (TraceLevel.Error, "mdoc: {0}", e.ToString ());
}
}
void RecurseDirectory (string dir)
{
string[] files = Directory.GetFiles (dir, "*.xml");
foreach (string f in files)
{
if (IsMonodocFile (f))
ValidateFile (f);
}
string[] dirs = Directory.GetDirectories (dir);
foreach (string d in dirs)
RecurseDirectory (d);
}
void OnValidationEvent (object sender, ValidationEventArgs a)
{
errors++;
Message (TraceLevel.Error, "mdoc: {0}", a.Message);
}
static bool IsMonodocFile (string file)
{
var dpath = Path.GetDirectoryName (file);
var dname = Path.GetFileName (dpath);
if (File.Exists (file) && Path.GetExtension (file).ToLower () == ".xml" && !dname.Equals(Consts.FrameworksIndex))
return true;
else
return false;
}
}
}

View File

@@ -52,7 +52,7 @@ namespace Mono.Documentation {
}
if (move) {
File.Delete (file);
DeleteFile (file);
File.Move (temp, file);
}
}
@@ -62,6 +62,26 @@ namespace Mono.Documentation {
}
}
public static void DeleteFile (string fileToDelete, int retries = 10)
{
var startRetries = retries;
var fi = new FileInfo(fileToDelete);
if (fi.Exists) {
fi.Delete ();
fi.Refresh ();
while (fi.Exists && retries-- > 0) {
System.Threading.Thread.Sleep (100);
fi.Refresh ();
}
fi.Refresh ();
if (fi.Exists)
throw new IOException ($"Unable to delete file '{fileToDelete}' after {startRetries} attempts.");
}
}
static bool FileContentsIdentical (Stream a, Stream b)
{
byte[] ba = new byte[4096];

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

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