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

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

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

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