Коммит
489be60c6a
|
@ -3,7 +3,7 @@ namespace Mono.Documentation
|
|||
{
|
||||
public static class Consts
|
||||
{
|
||||
public static string MonoVersion = "5.8.7";
|
||||
public static string MonoVersion = "5.8.8";
|
||||
public const string DocId = "DocId";
|
||||
public const string CppCli = "C++ CLI";
|
||||
public const string CppCx = "C++ CX";
|
||||
|
@ -49,5 +49,8 @@ namespace Mono.Documentation
|
|||
public const string IsByRefLikeAttribute = "System.Runtime.CompilerServices.IsByRefLikeAttribute";
|
||||
public const string IsReadOnlyAttribute = "System.Runtime.CompilerServices.IsReadOnlyAttribute";
|
||||
public const string InAttribute = "System.Runtime.InteropServices.InAttribute";
|
||||
public const string TupleElementNamesAttribute = "System.Runtime.CompilerServices.TupleElementNamesAttribute";
|
||||
public const string IsExternalInit = "System.Runtime.CompilerServices.IsExternalInit";
|
||||
public const string NativeIntegerAttribute = "System.Runtime.CompilerServices.NativeIntegerAttribute";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3997,7 +3997,7 @@ namespace Mono.Documentation
|
|||
xelement.RemoveAttribute(Consts.Index);
|
||||
xelement.SetAttribute(Consts.Index, i.ToString());
|
||||
xelement.SetAttribute (Consts.FrameworkAlternate, fxaValue);
|
||||
|
||||
MakeParamsAttributes(xelement, AttributeFormatter.PreProcessCustomAttributes(p.Definition.CustomAttributes), typeEntry, member);
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -3,6 +3,7 @@ using Mono.Cecil;
|
|||
using Mono.Documentation.Util;
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
|
||||
namespace Mono.Documentation.Updater
|
||||
{
|
||||
|
@ -10,9 +11,13 @@ namespace Mono.Documentation.Updater
|
|||
{
|
||||
private int nullableAttributeIndex;
|
||||
private int dynamicAttributeIndex;
|
||||
private int tupleNameAttributeIndex;
|
||||
private int nativeIntegerAttributeIndex;
|
||||
private ICustomAttributeProvider provider;
|
||||
private ReadOnlyCollection<bool?> nullableAttributeFlags;
|
||||
private ReadOnlyCollection<bool> dynamicAttributeFlags;
|
||||
private string[] tupleElementNames;
|
||||
private bool[] nativeIntegerFlags;
|
||||
|
||||
private AttributeParserContext(ICustomAttributeProvider provider)
|
||||
{
|
||||
|
@ -20,6 +25,8 @@ namespace Mono.Documentation.Updater
|
|||
|
||||
ReadDynamicAttribute();
|
||||
ReadNullableAttribute();
|
||||
ReadTupleElementNames();
|
||||
ReadNativeIntegerAttribute();
|
||||
}
|
||||
|
||||
private bool ExistsNullableAttribute
|
||||
|
@ -73,6 +80,16 @@ namespace Mono.Documentation.Updater
|
|||
return false;
|
||||
}
|
||||
|
||||
public string GetTupleElementName()
|
||||
{
|
||||
return (tupleElementNames == null || tupleNameAttributeIndex >= tupleElementNames.Length) ? null : tupleElementNames[tupleNameAttributeIndex++];
|
||||
}
|
||||
|
||||
public bool IsNativeInteger()
|
||||
{
|
||||
return nativeIntegerFlags != null && nativeIntegerAttributeIndex < nativeIntegerFlags.Length && nativeIntegerFlags[nativeIntegerAttributeIndex++];
|
||||
}
|
||||
|
||||
private void ReadDynamicAttribute()
|
||||
{
|
||||
DynamicTypeProvider dynamicTypeProvider = new DynamicTypeProvider(provider);
|
||||
|
@ -88,5 +105,31 @@ namespace Mono.Documentation.Updater
|
|||
NullableReferenceTypeProvider nullableReferenceTypeProvider = new NullableReferenceTypeProvider(provider);
|
||||
nullableAttributeFlags = new ReadOnlyCollection<bool?>(nullableReferenceTypeProvider.GetNullableReferenceTypeFlags());
|
||||
}
|
||||
|
||||
private void ReadTupleElementNames()
|
||||
{
|
||||
tupleElementNames = ReadCustomAttributeValue<string>(Consts.TupleElementNamesAttribute);
|
||||
}
|
||||
|
||||
private void ReadNativeIntegerAttribute()
|
||||
{
|
||||
nativeIntegerFlags = ReadCustomAttributeValue<bool>(
|
||||
Consts.NativeIntegerAttribute,
|
||||
() => new bool[] { true });
|
||||
}
|
||||
|
||||
private T[] ReadCustomAttributeValue<T>(string attributeName, Func<T[]> init = null)
|
||||
{
|
||||
if (provider == null || !provider.HasCustomAttributes) return null;
|
||||
|
||||
var customAttribute = provider.CustomAttributes.Where(attr => attr.AttributeType.FullName == attributeName).FirstOrDefault();
|
||||
|
||||
if (customAttribute == null) return null;
|
||||
|
||||
if (!customAttribute.HasConstructorArguments) return init?.Invoke();
|
||||
|
||||
var constructorArgs = customAttribute.ConstructorArguments[0].Value as CustomAttributeArgument[];
|
||||
return constructorArgs?.Select(arg => (T)arg.Value).ToArray();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -26,5 +26,15 @@
|
|||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public string GetTupleElementName()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool IsNativeInteger()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -77,15 +77,6 @@ namespace Mono.Documentation.Updater.Formatters
|
|||
return false;
|
||||
}
|
||||
|
||||
TypeDefinition attrType = attribute.AttributeType as TypeDefinition;
|
||||
if (attrType != null && !DocUtils.IsPublic(attrType)
|
||||
|| (FormatterManager.SlashdocFormatter.GetName(attribute.AttributeType) == null)
|
||||
|| Array.IndexOf(IgnorableAttributes, attribute.AttributeType.FullName) >= 0)
|
||||
{
|
||||
rval = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
var fields = new List<string>();
|
||||
|
||||
for (int i = 0; i < attribute.ConstructorArguments.Count; ++i)
|
||||
|
@ -127,11 +118,34 @@ namespace Mono.Documentation.Updater.Formatters
|
|||
|
||||
private bool IsIgnoredAttribute(CustomAttribute customAttribute)
|
||||
{
|
||||
var attrType = customAttribute.AttributeType;
|
||||
|
||||
if (attrType == null) return true;
|
||||
|
||||
// An Obsolete attribute with a known string is added to all ref-like structs
|
||||
// https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.2/span-safety.md#metadata-representation-or-ref-like-structs
|
||||
return customAttribute.AttributeType.FullName == typeof(ObsoleteAttribute).FullName
|
||||
if (attrType.FullName == typeof(ObsoleteAttribute).FullName
|
||||
&& customAttribute.HasConstructorArguments
|
||||
&& customAttribute.ConstructorArguments.First().Value.ToString() == Consts.RefTypeObsoleteString;
|
||||
&& customAttribute.ConstructorArguments.First().Value.ToString() == Consts.RefTypeObsoleteString)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Expose this attribute in ECMAXML to let ECMA2YML pick up
|
||||
// https://ceapex.visualstudio.com/Engineering/_workitems/edit/550401
|
||||
if (attrType.FullName == Consts.NativeIntegerAttribute)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var attrTypeDef = attrType as TypeDefinition;
|
||||
if (attrTypeDef != null && !DocUtils.IsPublic(attrTypeDef) || (FormatterManager.SlashdocFormatter.GetName(attrType) == null)
|
||||
|| Array.IndexOf(IgnorableAttributes, attrType.FullName) >= 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// FIXME: get TypeReferences instead of string comparison?
|
||||
|
|
|
@ -12,6 +12,12 @@ namespace Mono.Documentation.Updater.Formatters
|
|||
public CSharpFullMemberFormatter() : this(null) {}
|
||||
public CSharpFullMemberFormatter(TypeMap map) : base(map) { }
|
||||
|
||||
private static readonly Dictionary<string, string> NativeIntTypeMap = new Dictionary<string, string>()
|
||||
{
|
||||
{ "System.IntPtr", "nint" },
|
||||
{ "System.UIntPtr", "nuint" },
|
||||
};
|
||||
|
||||
public override string Language
|
||||
{
|
||||
get { return "C#"; }
|
||||
|
@ -25,7 +31,7 @@ namespace Mono.Documentation.Updater.Formatters
|
|||
return buf;
|
||||
}
|
||||
|
||||
protected virtual string GetCSharpType (string t)
|
||||
protected virtual string GetCSharpType(string t)
|
||||
{
|
||||
// make sure there are no modifiers in the type string (add them back before returning)
|
||||
string typeToCompare = t;
|
||||
|
@ -83,6 +89,11 @@ namespace Mono.Documentation.Updater.Formatters
|
|||
return base.AppendTypeName (buf, type, context);
|
||||
}
|
||||
|
||||
if (NativeIntTypeMap.TryGetValue(t, out string typeName) && context.IsNativeInteger())
|
||||
{
|
||||
return buf.Append(typeName);
|
||||
}
|
||||
|
||||
string s = GetCSharpType (t);
|
||||
if (s != null)
|
||||
{
|
||||
|
@ -137,7 +148,9 @@ namespace Mono.Documentation.Updater.Formatters
|
|||
if (genInst.Name.StartsWith ("ValueTuple`"))
|
||||
{
|
||||
buf.Append ("(");
|
||||
var genArgList = new List<string> ();
|
||||
var genArgTypeList = new List<string> ();
|
||||
// tuple element names should be traversed before recursion.
|
||||
var genArgNameList = genInst.GenericArguments.Select(arg => context.GetTupleElementName()).ToList();
|
||||
foreach (var item in genInst.GenericArguments)
|
||||
{
|
||||
var isNullableType = false;
|
||||
|
@ -147,11 +160,11 @@ namespace Mono.Documentation.Updater.Formatters
|
|||
}
|
||||
|
||||
var underlyingTypeName = GetTypeName (item, context, appendGeneric, useTypeProjection) + GetTypeNullableSymbol (item, isNullableType);
|
||||
genArgList.Add (underlyingTypeName);
|
||||
genArgTypeList.Add (underlyingTypeName);
|
||||
}
|
||||
buf.Append (string.Join (",", genArgList));
|
||||
var genArgList = genInst.GenericArguments.Select((_, index) => string.Format("{0}{1}", genArgTypeList[index], genArgNameList[index] == null ? String.Empty : (" " + genArgNameList[index])));
|
||||
buf.Append (string.Join (", ", genArgList));
|
||||
buf.Append (")");
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
@ -723,7 +736,14 @@ namespace Mono.Documentation.Updater.Formatters
|
|||
{
|
||||
if (set_visible != visibility)
|
||||
buf.Append (' ').Append (set_visible);
|
||||
buf.Append (" set;");
|
||||
if (property.SetMethod.ReturnType is RequiredModifierType returnType && returnType.ModifierType.FullName == Consts.IsExternalInit)
|
||||
{
|
||||
buf.Append(" init;");
|
||||
}
|
||||
else
|
||||
{
|
||||
buf.Append(" set;");
|
||||
}
|
||||
}
|
||||
buf.Append (" }");
|
||||
|
||||
|
|
|
@ -5,5 +5,7 @@
|
|||
void NextDynamicFlag();
|
||||
bool IsDynamic();
|
||||
bool IsNullable();
|
||||
string GetTupleElementName();
|
||||
bool IsNativeInteger();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -297,7 +297,7 @@ namespace mdoc.Test
|
|||
var member = GetMethod(typeof(NullablesAndTuples), m => m.Name == "TupleReturn");
|
||||
var formatter = new CSharpFullMemberFormatter();
|
||||
var sig = formatter.GetDeclaration(member);
|
||||
Assert.AreEqual("public (int,string) TupleReturn ();", sig);
|
||||
Assert.AreEqual("public (int, string) TupleReturn ();", sig);
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -420,6 +420,69 @@ namespace mdoc.Test
|
|||
Assert.AreEqual(expectedSignature, methodSignature);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CSharpTupleNamesTypeTest()
|
||||
{
|
||||
var type = GetType(typeof(SampleClasses.TupleNamesTestClass<,>));
|
||||
var typeSignature = formatter.GetDeclaration(type);
|
||||
Assert.AreEqual("public class TupleNamesTestClass<T1,T2> : IComparable<(T1, T2)>", typeSignature);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CSharpTupleNamesPropertyTest()
|
||||
{
|
||||
var property = GetProperty(typeof(SampleClasses.TupleNamesTestClass<,>), m => m.Name == "TuplePropertyType");
|
||||
var propertySignature = formatter.GetDeclaration(property);
|
||||
Assert.AreEqual("public (int a, int b) TuplePropertyType { get; }", propertySignature);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CSharpTupleNamesFieldTest()
|
||||
{
|
||||
var field = GetField(GetType(typeof(SampleClasses.TupleNamesTestClass<,>)), "TupleField");
|
||||
var fieldSignature = formatter.GetDeclaration(field);
|
||||
Assert.AreEqual("public (int a, int b, int c) TupleField;", fieldSignature);
|
||||
}
|
||||
|
||||
[TestCase("TupleMethod", "public (int a, int, int b) TupleMethod ((int, int) t1, (int b, int c, int d) t2, (int, int) t3);")]
|
||||
[TestCase("RecursiveTupleMethod", "public ((int a, long b) c, int d) RecursiveTupleMethod ((((int a, long) b, string c) d, (int e, (float f, float g) h) i, int j) t);")]
|
||||
public void CSharpTupleNamesMethodTest(string methodName, string expectedSignature)
|
||||
{
|
||||
var method = GetMethod(typeof(SampleClasses.TupleNamesTestClass<,>), m => m.Name == methodName);
|
||||
var methodSignature = formatter.GetDeclaration(method);
|
||||
Assert.AreEqual(expectedSignature, methodSignature);
|
||||
}
|
||||
|
||||
[TestCase("Property1", "public int Property1 { get; set; }")]
|
||||
[TestCase("Property2", "public int Property2 { get; init; }")]
|
||||
[TestCase("Property3", "public int Property3 { get; protected init; }")]
|
||||
[TestCase("Item", "public int this[int index] { get; init; }")]
|
||||
public void CSharpInitOnlySetterTest(string propertyName, string expectedSignature)
|
||||
{
|
||||
var property = GetProperty(typeof(SampleClasses.InitOnlySetter), p => p.Name == propertyName);
|
||||
var propertySignature = formatter.GetDeclaration(property);
|
||||
Assert.AreEqual(expectedSignature, propertySignature);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CSharpNativeIntGenericTypeTest()
|
||||
{
|
||||
var type = GetType(typeof(SampleClasses.GenericNativeIntClass<>));
|
||||
var typeSignature = formatter.GetDeclaration(type);
|
||||
Assert.AreEqual("public class GenericNativeIntClass<nint>", typeSignature);
|
||||
}
|
||||
|
||||
[TestCase("Method1", "public (nint, nuint) Method1 (nint a, nuint b, IntPtr c, UIntPtr d);")]
|
||||
[TestCase("Method2", "public (nint, nuint) Method2 (List<nint> a, Dictionary<int,nuint> b);")]
|
||||
[TestCase("Method3", "public (nint, nuint) Method3 ((nint, nuint) a, (nuint, IntPtr) b, (UIntPtr, string) c);")]
|
||||
[TestCase("Method4", "public (((nint a, IntPtr) b, UIntPtr c) d, (nint e, (nuint f, IntPtr g) h) i) Method4 ();")]
|
||||
public void CSharpNativeIntMethodTest(string methodName, string expectedSignature)
|
||||
{
|
||||
var method = GetMethod(typeof(SampleClasses.NativeIntClass), m => m.Name == methodName);
|
||||
var methodSignature = formatter.GetDeclaration(method);
|
||||
Assert.AreEqual(expectedSignature, methodSignature);
|
||||
}
|
||||
|
||||
#region Helper Methods
|
||||
string RealTypeName(string name){
|
||||
switch (name) {
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Xml;
|
||||
using mdoc.Test.SampleClasses;
|
||||
using Mono.Cecil;
|
||||
using Mono.Cecil.Rocks;
|
||||
using Mono.Collections.Generic;
|
||||
using Mono.Documentation;
|
||||
using Mono.Documentation.Updater;
|
||||
|
@ -31,6 +29,16 @@ namespace mdoc.Test
|
|||
Assert.IsFalse(formatter.TryGetAttributeString(attributes.First(), out string rval));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Test_GetCustomAttributes_EmitNativeIntegerAttribute()
|
||||
{
|
||||
var method = GetMethod(typeof(SampleClasses.NativeIntClass), "Method1");
|
||||
static CustomAttribute GetNativeIntegerAttr(ParameterDefinition p) => p?.CustomAttributes.Where(attr => attr.AttributeType.FullName == Consts.NativeIntegerAttribute).FirstOrDefault();
|
||||
Assert.IsNotNull(GetNativeIntegerAttr(method.Parameters[0]));
|
||||
Assert.IsTrue(formatter.TryGetAttributeString(GetNativeIntegerAttr(method.Parameters[0]), out string rval));
|
||||
Assert.IsNull(GetNativeIntegerAttr(method.Parameters[2]));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Test_GetDocParameterType_CppGenericParameterType_ReturnsTypeWithGenericParameters()
|
||||
{
|
||||
|
|
|
@ -36,10 +36,10 @@ namespace mdoc.Test
|
|||
[TestCase("Tuple<int,int>?", "NullableTupleOfValueType")]
|
||||
[TestCase("Tuple<int?,int?>", "TupleOfNullableValueType")]
|
||||
[TestCase("Tuple<int?,int?>?", "NullableTupleOfNullableValueType")]
|
||||
[TestCase("(int,int)", "ValueTupleOfValueType")]
|
||||
[TestCase("(int,int)?", "NullableValueTupleOfValueType")]
|
||||
[TestCase("(int?,int?)", "ValueTupleOfNullableValueType")]
|
||||
[TestCase("(int?,int?)?", "NullableValueTupleOfNullableValueType")]
|
||||
[TestCase("(int, int)", "ValueTupleOfValueType")]
|
||||
[TestCase("(int, int)?", "NullableValueTupleOfValueType")]
|
||||
[TestCase("(int?, int?)", "ValueTupleOfNullableValueType")]
|
||||
[TestCase("(int?, int?)?", "NullableValueTupleOfNullableValueType")]
|
||||
[TestCase("ICollection<int>", "InterfaceOfValueType")]
|
||||
[TestCase("ICollection<int>?", "NullableInterfaceOfValueType")]
|
||||
[TestCase("ICollection<int?>?", "NullableInterfaceOfNullableValueType")]
|
||||
|
@ -83,10 +83,10 @@ namespace mdoc.Test
|
|||
[TestCase("Tuple<string,string>?", "NullableTupleOfReferenceType")]
|
||||
[TestCase("Tuple<string?,string?>", "TupleOfNullableReferenceType")]
|
||||
[TestCase("Tuple<string?,string?>?", "NullableTupleOfNullableReferenceType")]
|
||||
[TestCase("(string,string)", "ValueTupleOfReferenceType")]
|
||||
[TestCase("(string,string)?", "NullableValueTupleOfReferenceType")]
|
||||
[TestCase("(string?,string?)", "ValueTupleOfNullableReferenceType")]
|
||||
[TestCase("(string?,string?)?", "NullableValueTupleOfNullableReferenceType")]
|
||||
[TestCase("(string, string)", "ValueTupleOfReferenceType")]
|
||||
[TestCase("(string, string)?", "NullableValueTupleOfReferenceType")]
|
||||
[TestCase("(string?, string?)", "ValueTupleOfNullableReferenceType")]
|
||||
[TestCase("(string?, string?)?", "NullableValueTupleOfNullableReferenceType")]
|
||||
[TestCase("ICollection<string>", "InterfaceOfReferenceType")]
|
||||
[TestCase("ICollection<string>?", "NullableInterfaceOfReferenceType")]
|
||||
[TestCase("ICollection<string?>?", "NullableInterfaceOfNullableReferenceType")]
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
namespace mdoc.Test.SampleClasses
|
||||
{
|
||||
public class InitOnlySetter
|
||||
{
|
||||
public int Property1 { get; set; }
|
||||
public int Property2 { get; init; }
|
||||
public int Property3 { get; protected init; }
|
||||
public int this[int index]
|
||||
{
|
||||
get
|
||||
{
|
||||
throw null;
|
||||
}
|
||||
init
|
||||
{
|
||||
throw null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
using System.ComponentModel;
|
||||
|
||||
namespace System.Runtime.CompilerServices
|
||||
{
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
internal class IsExternalInit { }
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace mdoc.Test.SampleClasses
|
||||
{
|
||||
public class NativeIntClass
|
||||
{
|
||||
public (nint, nuint) Method1(nint a, nuint b, IntPtr c, UIntPtr d)
|
||||
{
|
||||
return (a + c, b + d);
|
||||
}
|
||||
|
||||
public (nint, nuint) Method2(List<nint> a, Dictionary<int, nuint> b)
|
||||
{
|
||||
return (a[0], b[0]);
|
||||
}
|
||||
|
||||
public (nint, nuint) Method3((nint, nuint) a, (nuint, IntPtr) b, (UIntPtr, string) c)
|
||||
{
|
||||
return (a.Item1 + b.Item2, b.Item1 + c.Item1);
|
||||
}
|
||||
|
||||
public (((nint a, IntPtr) b, UIntPtr c) d, (nint e, (nuint f, IntPtr g) h) i) Method4() => throw null;
|
||||
}
|
||||
|
||||
public class GenericNativeIntClass<nint>
|
||||
{
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
using System;
|
||||
|
||||
namespace mdoc.Test.SampleClasses
|
||||
{
|
||||
public class TupleNamesTestClass<T1, T2> : IComparable<ValueTuple<T1, T2>>
|
||||
{
|
||||
public (int a, int b) TuplePropertyType { get; }
|
||||
|
||||
public (int a, int b, int c) TupleField;
|
||||
|
||||
public (int a, int, int b) TupleMethod((int, int) t1, (int b, int c, int d) t2, ValueTuple<int, int> t3) => (t1.Item1, t2.b, t3.Item2);
|
||||
|
||||
public ((int a, long b) c, int d) RecursiveTupleMethod((((int a, long) b, string c) d, (int e, (float f, float g) h) i, int j) t) => (t.d.b, t.j);
|
||||
|
||||
public int CompareTo((T1, T2) other)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,7 +2,7 @@
|
|||
<package >
|
||||
<metadata>
|
||||
<id>mdoc</id>
|
||||
<version>5.8.7</version>
|
||||
<version>5.8.8</version>
|
||||
<title>mdoc</title>
|
||||
<authors>Microsoft</authors>
|
||||
<owners>Microsoft</owners>
|
||||
|
|
Загрузка…
Ссылка в новой задаче