XmlDocsExtensions
Provides extension methods for reading XML comments from reflected members.
using Namotion.Reflection.Infrastructure;
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml.Linq;
namespace Namotion.Reflection
{
[System.Runtime.CompilerServices.NullableContext(1)]
[System.Runtime.CompilerServices.Nullable(0)]
public static class XmlDocsExtensions
{
[System.Runtime.CompilerServices.Nullable(new byte[] {
1,
1,
2
})]
private static readonly ConcurrentDictionary<string, CachingXDocument> Cache = new ConcurrentDictionary<string, CachingXDocument>(StringComparer.OrdinalIgnoreCase);
private static readonly char[] ToXmlDocsContentTrimChars = new char[2] {
'!',
':'
};
private static readonly char[] RemoveLineBreakWhiteSpacesTrimChars = new char[1] {
'\n'
};
private static readonly Regex LineBreakRegex = new Regex("(\\n[ \\t]*)", RegexOptions.Compiled);
private static readonly Regex runtimeConfigRegex = new Regex("\"((.*?)((\\\\\\\\)|(////))(.*?))\"", RegexOptions.IgnoreCase);
internal static void ClearCache()
{
Cache.Clear();
}
public static string GetXmlDocsSummary(this CachedType type, [System.Runtime.CompilerServices.Nullable(2)] XmlDocsOptions options = null)
{
return type.Type.GetXmlDocsSummary(options);
}
public static string GetXmlDocsRemarks(this CachedType type, [System.Runtime.CompilerServices.Nullable(2)] XmlDocsOptions options = null)
{
return type.Type.GetXmlDocsRemarks(options);
}
public static string GetXmlDocsTag(this CachedType type, string tagName, [System.Runtime.CompilerServices.Nullable(2)] XmlDocsOptions options = null)
{
return type.Type.GetXmlDocsTag(tagName, options);
}
public static string GetXmlDocsSummary(this ContextualMemberInfo member, [System.Runtime.CompilerServices.Nullable(2)] XmlDocsOptions options = null)
{
return member.MemberInfo.GetXmlDocsSummary(options);
}
public static string GetXmlDocsRemarks(this ContextualMemberInfo member, [System.Runtime.CompilerServices.Nullable(2)] XmlDocsOptions options = null)
{
return member.MemberInfo.GetXmlDocsRemarks(options);
}
public static string GetXmlDocsTag(this ContextualMemberInfo member, string tagName, [System.Runtime.CompilerServices.Nullable(2)] XmlDocsOptions options = null)
{
return member.MemberInfo.GetXmlDocsTag(tagName, options);
}
public static string GetXmlDocs(this ContextualParameterInfo parameter, [System.Runtime.CompilerServices.Nullable(2)] XmlDocsOptions options = null)
{
return parameter.ParameterInfo.GetXmlDocs(options);
}
public static string GetXmlDocsSummary(this Type type, [System.Runtime.CompilerServices.Nullable(2)] XmlDocsOptions options = null)
{
return ((MemberInfo)type.GetTypeInfo()).GetXmlDocsTag("summary", options);
}
public static string GetXmlDocsRemarks(this Type type, [System.Runtime.CompilerServices.Nullable(2)] XmlDocsOptions options = null)
{
return ((MemberInfo)type.GetTypeInfo()).GetXmlDocsTag("remarks", options);
}
public static string GetXmlDocsTag(this Type type, string tagName, [System.Runtime.CompilerServices.Nullable(2)] XmlDocsOptions options = null)
{
return ((MemberInfo)type.GetTypeInfo()).GetXmlDocsTag(tagName, options);
}
public static string GetXmlDocsSummary(this MemberInfo member, [System.Runtime.CompilerServices.Nullable(2)] XmlDocsOptions options = null)
{
string xmlDocsTag = member.GetXmlDocsTag("summary", options);
if (string.IsNullOrEmpty(xmlDocsTag)) {
PropertyInfo propertyInfo = member as PropertyInfo;
if ((object)propertyInfo != null)
return propertyInfo.GetXmlDocsRecordPropertySummary(options);
}
return xmlDocsTag;
}
public static string GetXmlDocsRemarks(this MemberInfo member, [System.Runtime.CompilerServices.Nullable(2)] XmlDocsOptions options = null)
{
return member.GetXmlDocsTag("remarks", options);
}
[System.Runtime.CompilerServices.NullableContext(2)]
public static XElement GetXmlDocsElement([System.Runtime.CompilerServices.Nullable(1)] this MemberInfo member, XmlDocsOptions options = null)
{
options = (options ?? XmlDocsOptions.Default);
if (IsAssemblyIgnored(member.Module.Assembly.GetName(), options.ResolveExternalXmlDocs))
return null;
string xmlDocsPath = GetXmlDocsPath(member.Module.Assembly, options);
return member.GetXmlDocsElement(xmlDocsPath, options);
}
[return: System.Runtime.CompilerServices.Nullable(2)]
public static XElement GetXmlDocsElement(this MemberInfo member, string pathToXmlFile, [System.Runtime.CompilerServices.Nullable(2)] XmlDocsOptions options = null)
{
try {
options = (options ?? XmlDocsOptions.Default);
CachingXDocument cachingXDocument = TryGetXmlDocsDocument(member.Module.Assembly.GetName(), pathToXmlFile, options.ResolveExternalXmlDocs);
if (cachingXDocument != null) {
XElement xmlDocsElement = member.GetXmlDocsElement(cachingXDocument);
member.ReplaceInheritdocElements(xmlDocsElement, options);
return xmlDocsElement;
}
return null;
} catch {
return null;
}
}
public static string GetXmlDocsTag(this MemberInfo member, string tagName, [System.Runtime.CompilerServices.Nullable(2)] XmlDocsOptions options = null)
{
options = (options ?? XmlDocsOptions.Default);
if ((object)member == null)
throw new ArgumentNullException("member");
if (tagName == null)
throw new ArgumentNullException("tagName");
if (IsAssemblyIgnored(member.Module.Assembly.GetName(), options.ResolveExternalXmlDocs))
return string.Empty;
string xmlDocsPath = GetXmlDocsPath(member.Module.Assembly, options);
return (member.GetXmlDocsElement(xmlDocsPath, options)?.Element(tagName)).ToXmlDocsContent(options);
}
public static string GetXmlDocsRecordPropertySummary(this PropertyInfo member, [System.Runtime.CompilerServices.Nullable(2)] XmlDocsOptions options = null)
{
options = (options ?? XmlDocsOptions.Default);
if ((object)member == null)
throw new ArgumentNullException("member");
if (IsAssemblyIgnored(member.Module.Assembly.GetName(), options.ResolveExternalXmlDocs))
return string.Empty;
string xmlDocsPath = GetXmlDocsPath(member.Module.Assembly, options);
XElement xmlDocsElement = member.DeclaringType.GetTypeInfo().GetXmlDocsElement(xmlDocsPath, options);
object obj;
if (xmlDocsElement == null)
obj = null;
else {
IEnumerable<XElement> enumerable = xmlDocsElement.Elements("param");
obj = ((enumerable != null) ? enumerable.FirstOrDefault((XElement x) => x.Attribute("name")?.Value == member.Name) : null);
}
XElement xElement = (XElement)obj;
if (xElement == null)
return string.Empty;
return xElement.ToXmlDocsContent(options);
}
public static string GetXmlDocs(this ParameterInfo parameter, [System.Runtime.CompilerServices.Nullable(2)] XmlDocsOptions options = null)
{
options = (options ?? XmlDocsOptions.Default);
if (IsAssemblyIgnored(parameter.Member.Module.Assembly.GetName(), options.ResolveExternalXmlDocs))
return string.Empty;
string xmlDocsPath = GetXmlDocsPath(parameter.Member.Module.Assembly, options);
return parameter.GetXmlDocs(xmlDocsPath, options).ToXmlDocsContent(options);
}
[return: System.Runtime.CompilerServices.Nullable(2)]
public static XElement GetXmlDocsElement(this ParameterInfo parameter, string pathToXmlFile, [System.Runtime.CompilerServices.Nullable(2)] XmlDocsOptions options = null)
{
try {
if (pathToXmlFile != null)
return parameter.GetXmlDocs(pathToXmlFile, options ?? XmlDocsOptions.Default);
return null;
} catch {
return null;
}
}
[System.Runtime.CompilerServices.NullableContext(2)]
[return: System.Runtime.CompilerServices.Nullable(1)]
public static string ToXmlDocsContent(this XElement element, XmlDocsOptions options = null)
{
if (options == null)
options = XmlDocsOptions.Default;
if (element != null) {
StringBuilder stringBuilder = new StringBuilder();
foreach (XNode item in element.Nodes()) {
XElement xElement = item as XElement;
if (xElement != null) {
if (xElement.Name == (XName)"see") {
XAttribute xAttribute = xElement.Attribute("langword");
if (xAttribute != null)
stringBuilder.Append(xAttribute.Value);
else if (!string.IsNullOrEmpty(xElement.Value)) {
stringBuilder.AppendFormattedElement(xElement, options.FormattingMode);
} else {
xAttribute = xElement.Attribute("cref");
if (xAttribute != null) {
string s = xAttribute.Value.Trim(ToXmlDocsContentTrimChars).Trim();
s = s.FirstToken('(');
s = s.LastToken('.');
stringBuilder.Append(s);
} else {
xAttribute = xElement.Attribute("href");
if (xAttribute != null)
stringBuilder.Append(xAttribute.Value);
}
}
} else if (xElement.Name == (XName)"paramref") {
stringBuilder.Append(xElement.Attribute("name")?.Value ?? xElement.Value);
} else {
stringBuilder.AppendFormattedElement(xElement, options.FormattingMode);
}
} else {
XText xText = item as XText;
if (xText != null)
stringBuilder.Append(xText.Value);
else
stringBuilder.Append(item);
}
}
return RemoveLineBreakWhiteSpaces(stringBuilder.ToString());
}
return string.Empty;
}
[return: System.Runtime.CompilerServices.Nullable(2)]
private static XElement GetXmlDocs(this ParameterInfo parameter, [System.Runtime.CompilerServices.Nullable(2)] string pathToXmlFile, XmlDocsOptions options)
{
try {
CachingXDocument cachingXDocument = TryGetXmlDocsDocument(parameter.Member.Module.Assembly.GetName(), pathToXmlFile, options.ResolveExternalXmlDocs);
if (cachingXDocument != null)
return parameter.GetXmlDocsElement(cachingXDocument, options);
return null;
} catch {
return null;
}
}
[System.Runtime.CompilerServices.NullableContext(2)]
private static CachingXDocument TryGetXmlDocsDocument([System.Runtime.CompilerServices.Nullable(1)] AssemblyName assemblyName, string pathToXmlFile, bool resolveExternalXmlDocs)
{
string cacheKey = GetCacheKey(assemblyName.FullName, resolveExternalXmlDocs);
if (Cache.TryGetValue(cacheKey, out CachingXDocument value))
return value;
if (pathToXmlFile == null)
return null;
if (!DynamicApis.FileExists(pathToXmlFile)) {
Cache[cacheKey] = null;
return null;
}
value = new CachingXDocument(pathToXmlFile);
Cache[cacheKey] = value;
return value;
}
private static bool IsAssemblyIgnored(AssemblyName assemblyName, bool resolveExternalXmlDocs)
{
if (Cache.TryGetValue(GetCacheKey(assemblyName.FullName, resolveExternalXmlDocs), out CachingXDocument value))
return value == null;
return false;
}
[return: System.Runtime.CompilerServices.Nullable(2)]
private static XElement GetXmlDocsElement(this MemberInfo member, CachingXDocument xml)
{
string memberElementName = GetMemberElementName(member);
return xml.GetXmlDocsElement(memberElementName);
}
[return: System.Runtime.CompilerServices.Nullable(2)]
internal static XElement GetXmlDocsElement(this XDocument xml, string name)
{
return CachingXDocument.GetXmlDocsElement(xml, name);
}
[return: System.Runtime.CompilerServices.Nullable(2)]
private static XElement GetXmlDocsElement(this ParameterInfo parameter, CachingXDocument xml, XmlDocsOptions options)
{
string memberElementName = GetMemberElementName(parameter.Member);
XElement xmlDocsElement = xml.GetXmlDocsElement(memberElementName);
if (xmlDocsElement != null) {
parameter.Member.ReplaceInheritdocElements(xmlDocsElement, options);
IEnumerable source = (!parameter.IsRetval && !string.IsNullOrEmpty(parameter.Name)) ? (from x in xmlDocsElement.Elements("param")
where x.Attribute("name")?.Value == parameter.Name
select x) : xmlDocsElement.Elements("returns");
return source.OfType<XElement>().FirstOrDefault();
}
return null;
}
private static void ReplaceInheritdocElements(this MemberInfo member, [System.Runtime.CompilerServices.Nullable(2)] XElement element, XmlDocsOptions options)
{
if (element != null) {
foreach (XElement item in element.Nodes().ToList().OfType<XElement>()) {
if (item.Name.LocalName.ToLowerInvariant() == "inheritdoc") {
bool flag = item.HasAttributes;
if (flag) {
MemberTypes memberType = member.MemberType;
bool flag2 = (memberType == MemberTypes.Property || memberType == MemberTypes.TypeInfo) ? true : false;
flag = flag2;
}
if (flag)
member.ProcessInheritDocTypeElements(item, options);
else {
Type declaringType = member.DeclaringType;
Type obj = ((object)declaringType != null) ? declaringType.GetTypeInfo().BaseType : null;
MemberInfo memberInfo = ((object)obj != null) ? obj.GetTypeInfo().DeclaredMembers.SingleOrDefault((MemberInfo m) => m.Name == member.Name) : null;
if (memberInfo != (MemberInfo)null) {
XElement xmlDocsElement = memberInfo.GetXmlDocsElement(options);
if (xmlDocsElement != null) {
object[] content = xmlDocsElement.Nodes().OfType<object>().ToArray();
item.ReplaceWith(content);
} else
member.ProcessInheritdocInterfaceElements(item, options);
} else
member.ProcessInheritdocInterfaceElements(item, options);
}
}
}
}
}
private static void ProcessInheritdocInterfaceElements(this MemberInfo member, XElement child, XmlDocsOptions options)
{
Type declaringType = member.DeclaringType;
if ((((object)declaringType != null) ? declaringType.GetTypeInfo().ImplementedInterfaces : null) != null) {
foreach (Type implementedInterface in member.DeclaringType.GetTypeInfo().ImplementedInterfaces) {
MemberInfo memberInfo = ((object)implementedInterface != null) ? implementedInterface.GetTypeInfo().DeclaredMembers.SingleOrDefault((MemberInfo m) => m.Name == member.Name) : null;
if (memberInfo != (MemberInfo)null) {
XElement xmlDocsElement = memberInfo.GetXmlDocsElement(options);
if (xmlDocsElement != null) {
object[] content = xmlDocsElement.Nodes().OfType<object>().ToArray();
child.ReplaceWith(content);
}
}
}
}
}
private static string RemoveLineBreakWhiteSpaces([System.Runtime.CompilerServices.Nullable(2)] string documentation)
{
if (string.IsNullOrEmpty(documentation))
return string.Empty;
documentation = "\n" + documentation.Replace("\r", string.Empty).Trim(RemoveLineBreakWhiteSpacesTrimChars);
string value = LineBreakRegex.Match(documentation).Value;
documentation = documentation.Replace(value, "\n");
return documentation.Trim(RemoveLineBreakWhiteSpacesTrimChars);
}
internal static string GetMemberElementName(dynamic member)
{
if ((object)member == null)
throw new ArgumentNullException("member");
MemberInfo memberInfo = member as MemberInfo;
if ((object)memberInfo != null && memberInfo.DeclaringType != (Type)null && memberInfo.DeclaringType.GetTypeInfo().IsGenericType) {
PropertyInfo propertyInfo = member as PropertyInfo;
member = (((object)propertyInfo == null) ? member.Module.ResolveMember(member.MetadataToken) : propertyInfo.DeclaringType.GetRuntimeProperty(propertyInfo.Name));
}
Type type = ((object)member).GetType();
string text;
string text2;
if (type.FullName.Contains(".Cecil.")) {
text = (string)(type.IsAssignableToTypeName("TypeDefinition", TypeNameStyle.Name) ? member.FullName : (member.DeclaringType.FullName + "." + member.Name));
text = text.Replace("/", ".").Replace('+', '.');
text2 = ((!type.IsAssignableToTypeName("MethodDefinition", TypeNameStyle.Name)) ? (type.IsAssignableToTypeName("PropertyDefinition", TypeNameStyle.Name) ? "Property" : (type.IsAssignableToTypeName("FieldDefinition", TypeNameStyle.Name) ? "Field" : "TypeInfo")) : (text.EndsWith("..ctor") ? "Constructor" : "Method"));
} else {
Type type2 = member as Type;
text = (string)(((object)type2 != null && !string.IsNullOrEmpty(type.FullName)) ? type2.FullName.FirstToken('[') : (((string)member.DeclaringType.FullName).FirstToken('[') + "." + member.Name));
text2 = (string)member.MemberType.ToString();
}
if (text2 != null) {
char c;
Func<object, string> func;
object enumerable2;
IEnumerable<string> source;
string text3;
switch (text2.Length) {
case 5:
switch (text2[0]) {
case 'E':
break;
case 'F':
goto IL_0781;
default:
goto IL_0a11;
}
if (!(text2 == "Event"))
break;
c = 'E';
goto IL_0a21;
case 8:
switch (text2[0]) {
case 'T':
break;
case 'P':
goto IL_07c0;
default:
goto IL_0a11;
}
if (!(text2 == "TypeInfo"))
break;
goto IL_0a07;
case 11:
if (!(text2 == "Constructor"))
break;
text = text.Replace(".ctor", "#ctor");
goto IL_07e6;
case 6:
if (!(text2 == "Method"))
break;
goto IL_07e6;
case 10:
{
if (!(text2 == "NestedType"))
break;
text = text.Replace('+', '.');
goto IL_0a07;
}
IL_0781:
if (!(text2 == "Field"))
break;
c = 'F';
goto IL_0a21;
IL_07e6:
c = 'M';
func = delegate(dynamic p) {
object obj;
if (!(p.ParameterType.ContainsGenericParameter ? true : false))
obj = (string)p.ParameterType.FullName;
else {
object obj2 = ObjectExtensions.HasProperty(p.ParameterType, "GenericArguments");
obj = (((((dynamic)obj2) ? false : true) ? obj2 : ((dynamic)obj2 & (p.ParameterType.GenericArguments.Count > 0))) ? (((string)p.ParameterType.FullName).FirstToken('`') + "{" + string.Join(",", from object u in (ICollection)p.ParameterType.GenericArguments
select "||" + u.Position) + "}") : ("||" + p.ParameterType.Position));
}
return (string)obj;
};
if (!(member is MethodBase)) {
IEnumerable<string> enumerable = (IEnumerable<string>)Enumerable.Select<object, string>(member.Parameters, func);
enumerable2 = enumerable;
} else
enumerable2 = ((MethodBase)member).GetParameters().Select(delegate(ParameterInfo x) {
object text4 = x.ParameterType.FullName;
if (text4 == null) {
if (!((((dynamic)x.ParameterType).GenericTypeArguments.Length > 0) ? true : false))
return "||" + x.ParameterType.GenericParameterPosition.ToString();
text4 = x.ParameterType.Namespace + "." + x.ParameterType.Name.FirstToken('`') + "{" + string.Join(",", ((Type[])((dynamic)x.ParameterType).GenericTypeArguments).Select(delegate(Type a) {
if (!a.IsGenericParameter)
return a.Namespace + "." + a.Name + "[[||0]]";
return "||" + a.GenericParameterPosition.ToString();
})) + "}";
}
return (string)text4;
});
source = (IEnumerable<string>)enumerable2;
text3 = string.Join(",", (from x in source
select Regex.Replace(x, "(`[0-9]+)|(, .*?PublicKeyToken=[0-9a-z]*)", string.Empty).Replace("],[", ",").Replace("||", "`")
.Replace("[[", "{")
.Replace("[]]]", "[]}")
.Replace("]]", "}")).ToArray());
if (!string.IsNullOrEmpty(text3))
text = text + "(" + text3 + ")";
goto IL_0a21;
IL_0a21:
return string.Format("{0}:{1}", c, text.Replace("+", "."));
IL_07c0:
if (!(text2 == "Property"))
break;
c = 'P';
goto IL_0a21;
IL_0a07:
c = 'T';
goto IL_0a21;
}
}
goto IL_0a11;
IL_0a11:
throw new ArgumentException("Unknown member type.", "member");
}
[System.Runtime.CompilerServices.NullableContext(2)]
public static string GetXmlDocsPath(Assembly assembly, [System.Runtime.CompilerServices.Nullable(1)] XmlDocsOptions options)
{
try {
if (!(assembly == (Assembly)null)) {
AssemblyName name = assembly.GetName();
if (!string.IsNullOrEmpty(name.Name)) {
string cacheKey = GetCacheKey(name.FullName, options.ResolveExternalXmlDocs);
if (!Cache.ContainsKey(cacheKey))
try {
string text;
if (!string.IsNullOrEmpty(assembly.Location)) {
text = DynamicApis.PathCombine(DynamicApis.PathGetDirectoryName(assembly.Location), name.Name + ".xml");
if (DynamicApis.FileExists(text))
return text;
}
if (assembly.HasProperty("CodeBase")) {
string codeBase = assembly.CodeBase;
if (!string.IsNullOrEmpty(codeBase)) {
text = DynamicApis.PathCombine(DynamicApis.PathGetDirectoryName(codeBase.Replace("file:///", string.Empty)), name.Name + ".xml").Replace("file:\\", string.Empty);
if (DynamicApis.FileExists(text))
return text;
}
}
Type type = Type.GetType("System.AppDomain");
object obj = ((object)type == null) ? null : type.GetRuntimeProperty("CurrentDomain")?.GetValue(null);
if (obj != null && obj.HasProperty("BaseDirectory")) {
string text2 = obj.TryGetPropertyValue("BaseDirectory", "");
if (!string.IsNullOrEmpty(text2)) {
text = DynamicApis.PathCombine(text2, name.Name + ".xml");
if (DynamicApis.FileExists(text))
return text;
text = DynamicApis.PathCombine(text2, "bin/" + name.Name + ".xml");
if (DynamicApis.FileExists(text))
return text;
}
}
string path = DynamicApis.DirectoryGetCurrentDirectory();
text = DynamicApis.PathCombine(path, assembly.GetName().Name + ".xml");
if (!DynamicApis.FileExists(text)) {
text = DynamicApis.PathCombine(path, "bin/" + assembly.GetName().Name + ".xml");
if (!DynamicApis.FileExists(text)) {
if (options.ResolveExternalXmlDocs) {
text = GetXmlDocsPathFromOSXNuGetCache(assembly, name);
if (DynamicApis.FileExists(text))
return text;
dynamic val = typeof(Assembly).GetRuntimeMethod("GetExecutingAssembly", new Type[0])?.Invoke(null, new object[0]);
if ((!string.IsNullOrEmpty(val?.Location))) {
text = GetXmlDocsPathFromNuGetCacheOrDotNetSdk(DynamicApis.PathGetDirectoryName((string)val.Location), name);
if (text != null && DynamicApis.FileExists(text))
return text;
}
}
Cache[cacheKey] = null;
return null;
}
return text;
}
return text;
} catch {
Cache[cacheKey] = null;
return null;
}
return null;
}
return null;
}
return null;
} catch {
return null;
}
}
private static void ProcessInheritDocTypeElements(this MemberInfo member, XElement child, XmlDocsOptions options)
{
string text = child.Attribute("cref")?.Value;
if (text != null) {
MemberInfo referencedType = null;
Assembly assembly = null;
string text2 = (text[0] != 'P') ? Regex.Match(text, "[A-Z]:(?<FullName>(?<Namespace>[a-zA-Z.]*)\\.(?<TypeName>[a-zA-Z]*))").Groups["FullName"].Value : Regex.Match(text, "(?<FullName>(?<FullTypeName>(?<AssemblyName>[a-zA-Z.]*)\\.(?<TypeName>[a-zA-Z]*))\\.(?<MemberName>[a-zA-Z]*))").Groups["FullTypeName"].Value;
if ((object)assembly == null && text2 != null) {
assembly = member.Module.Assembly;
referencedType = assembly.GetType(text2);
if ((object)referencedType == null) {
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
foreach (Assembly assembly2 in assemblies) {
if (text.Contains(assembly2.GetName().Name)) {
referencedType = GetTypeByXmlDocTypeName(text2, assembly2);
if (referencedType != (MemberInfo)null) {
assembly = assembly2;
break;
}
}
}
}
}
if ((object)referencedType != null && (object)assembly != null) {
XElement xElement = TryGetXmlDocsDocument(assembly.GetName(), GetXmlDocsPath(assembly, options), true)?.GetXmlDocsElement(text);
if (xElement == null && referencedType.MemberType == MemberTypes.Property) {
string xmlDocsPath = GetXmlDocsPath(member.Module.Assembly, options);
if (xmlDocsPath != null) {
XElement xmlDocsElement = referencedType.DeclaringType.GetTypeInfo().GetXmlDocsElement(xmlDocsPath, options);
object obj;
if (xmlDocsElement == null)
obj = null;
else {
IEnumerable<XElement> enumerable = xmlDocsElement.Elements("param");
obj = ((enumerable != null) ? enumerable.FirstOrDefault((XElement x) => x.Attribute("name")?.Value == referencedType.Name) : null);
}
xElement = (XElement)obj;
child.ReplaceWith(xElement);
}
} else if (xElement != null) {
object[] content = xElement.Nodes().OfType<object>().ToArray();
child.ReplaceWith(content);
}
}
}
}
[return: System.Runtime.CompilerServices.Nullable(2)]
private static Type GetTypeByXmlDocTypeName(string xmlDocTypeName, Assembly assembly)
{
(from type in assembly.GetTypes()
select new KeyValuePair<string, Type>(NormalizeTypeName(type.FullName), type)).ToDictionary((KeyValuePair<string, Type> x) => x.Key, (KeyValuePair<string, Type> x) => x.Value).TryGetValue(NormalizeTypeName(xmlDocTypeName), out Type value);
return value;
}
private static string NormalizeTypeName(string typeName)
{
return typeName.Replace(".", string.Empty).Replace("+", string.Empty);
}
[System.Runtime.CompilerServices.NullableContext(2)]
private static string GetXmlDocsPathFromOSXNuGetCache(dynamic assembly, [System.Runtime.CompilerServices.Nullable(1)] AssemblyName assemblyName)
{
return null;
}
[return: System.Runtime.CompilerServices.Nullable(2)]
private static string GetXmlDocsPathFromNuGetCacheOrDotNetSdk(string assemblyDirectory, AssemblyName assemblyName)
{
string[] source = DynamicApis.DirectoryGetFiles(assemblyDirectory, "*.runtimeconfig.dev.json");
if (source.Any())
try {
string input = DynamicApis.FileReadAllText(source.First());
MatchCollection matchCollection = runtimeConfigRegex.Matches(input);
if (matchCollection.Count > 0) {
foreach (Match item in matchCollection) {
string text = item.Groups[1].Value.Replace("\\\\", "/").Replace("//", "/").Replace("\\|arch|", "")
.Replace("\\|tfm|", "")
.Replace("/|arch|", "")
.Replace("/|tfm|", "");
if (DynamicApis.DirectoryExists(text))
try {
string text2 = DynamicApis.PathCombine(text, assemblyName.Name + "/" + assemblyName.Version.ToString(3));
if (DynamicApis.DirectoryExists(text2)) {
string text3 = (from f in DynamicApis.DirectoryGetAllFiles(text2, assemblyName.Name + ".xml")
orderby f descending
select f).FirstOrDefault();
if (text3 != null)
return text3;
}
} catch {
}
if (text.Contains("/dotnet/sdk")) {
string search;
while ((text = DynamicApis.PathGetDirectoryName(text).Replace('\\', '/')) != null) {
if (text.EndsWith("/dotnet")) {
try {
text = DynamicApis.PathCombine(text, "packs");
search = "/" + assemblyName.Version.ToString(2);
string text4 = (from f in DynamicApis.DirectoryGetAllFiles(text, assemblyName.Name + ".xml")
where f.Replace('\\', '/').Contains(search)
orderby f descending
select f).FirstOrDefault();
if (text4 != null)
return text4;
} catch {
}
break;
}
}
}
}
}
} catch {
}
string text5 = DynamicApis.PathCombine(assemblyDirectory, "../../obj/project.nuget.cache");
if (DynamicApis.FileExists(text5))
return GetXmlDocsPathFromNuGetCacheFile(text5, assemblyName);
text5 = DynamicApis.PathCombine(assemblyDirectory, "../../../obj/project.nuget.cache");
if (DynamicApis.FileExists(text5))
return GetXmlDocsPathFromNuGetCacheFile(text5, assemblyName);
text5 = DynamicApis.PathCombine(assemblyDirectory.Replace("/bin/", "/obj/"), "../project.nuget.cache");
if (DynamicApis.FileExists(text5))
return GetXmlDocsPathFromNuGetCacheFile(text5, assemblyName);
return null;
}
[return: System.Runtime.CompilerServices.Nullable(2)]
private static string GetXmlDocsPathFromNuGetCacheFile(string nuGetCacheFile, AssemblyName assemblyName)
{
try {
MatchCollection matchCollection = Regex.Matches(DynamicApis.FileReadAllText(nuGetCacheFile), "\"((.*?)" + assemblyName.Name + "((\\\\\\\\)|/).*?)((\\\\\\\\)|/)(.*?)\"", RegexOptions.IgnoreCase);
if (matchCollection.Count > 0) {
string[] source = DynamicApis.DirectoryGetAllFiles(matchCollection[0].Groups[1].Value.Replace("\\\\", "\\").Replace("//", "/"), assemblyName.Name + ".xml");
if (source.Any())
return source.Last();
}
return null;
} catch {
return null;
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static string GetCacheKey(string assemblyFullName, bool resolveExternalXmlDocs)
{
return $"{assemblyFullName}""{resolveExternalXmlDocs}";
}
}
}