Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/api-doc-tools.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMin Huang <huangmin@microsoft.com>2022-03-21 06:17:32 +0300
committerGitHub <noreply@github.com>2022-03-21 06:17:32 +0300
commitb24bc75b10a6a2fb6987546b96559c5768ba7093 (patch)
tree8e59c30b7e0d070e69abb52a1ba8190d248cd22a
parent4cf39bde45ffdeddec87aad9edce7f2c0f78b9ee (diff)
feat#550401:Support C# 9 nint/nuint (#620)
* Support C# 9 nint/nuint * update * update * update * update * update * update * update * update * fix test cases * fix test cases * fix integration test * add unit test
-rw-r--r--mdoc/Consts.cs1
-rw-r--r--mdoc/Mono.Documentation/Updater/AttributeParserContext.cs39
-rw-r--r--mdoc/Mono.Documentation/Updater/EmptyAttributeParserContext.cs5
-rw-r--r--mdoc/Mono.Documentation/Updater/Formatters/AttributeFormatters/AttributeFormatter.cs36
-rw-r--r--mdoc/Mono.Documentation/Updater/Formatters/CSharpFullMemberFormatter.cs15
-rw-r--r--mdoc/Mono.Documentation/Updater/IAttributeParserContext.cs1
-rw-r--r--mdoc/mdoc.Test/FormatterTests.cs31
-rw-r--r--mdoc/mdoc.Test/MDocUpdaterTests.cs12
-rw-r--r--mdoc/mdoc.Test/NullableReferenceTypesTests.cs16
-rw-r--r--mdoc/mdoc.Test/SampleClasses/NativeIntClass.cs30
10 files changed, 148 insertions, 38 deletions
diff --git a/mdoc/Consts.cs b/mdoc/Consts.cs
index e047f2af..cc165d1f 100644
--- a/mdoc/Consts.cs
+++ b/mdoc/Consts.cs
@@ -51,5 +51,6 @@ namespace Mono.Documentation
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";
}
}
diff --git a/mdoc/Mono.Documentation/Updater/AttributeParserContext.cs b/mdoc/Mono.Documentation/Updater/AttributeParserContext.cs
index e294d7cb..a472ec10 100644
--- a/mdoc/Mono.Documentation/Updater/AttributeParserContext.cs
+++ b/mdoc/Mono.Documentation/Updater/AttributeParserContext.cs
@@ -12,10 +12,12 @@ 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)
{
@@ -24,6 +26,7 @@ namespace Mono.Documentation.Updater
ReadDynamicAttribute();
ReadNullableAttribute();
ReadTupleElementNames();
+ ReadNativeIntegerAttribute();
}
private bool ExistsNullableAttribute
@@ -82,6 +85,11 @@ namespace Mono.Documentation.Updater
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);
@@ -100,15 +108,28 @@ namespace Mono.Documentation.Updater
private void ReadTupleElementNames()
{
- if (provider != null && provider.HasCustomAttributes)
- {
- var tupleNamesAttr = provider.CustomAttributes.Where(attr => attr.AttributeType.FullName == Consts.TupleElementNamesAttribute).FirstOrDefault();
- if (tupleNamesAttr != null)
- {
- var constructorArgs = tupleNamesAttr.ConstructorArguments.FirstOrDefault().Value as CustomAttributeArgument[];
- tupleElementNames = constructorArgs?.Select(arg => arg.Value as string).ToArray();
- }
- }
+ 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();
}
}
} \ No newline at end of file
diff --git a/mdoc/Mono.Documentation/Updater/EmptyAttributeParserContext.cs b/mdoc/Mono.Documentation/Updater/EmptyAttributeParserContext.cs
index 71b638fd..c21a8222 100644
--- a/mdoc/Mono.Documentation/Updater/EmptyAttributeParserContext.cs
+++ b/mdoc/Mono.Documentation/Updater/EmptyAttributeParserContext.cs
@@ -31,5 +31,10 @@
{
return null;
}
+
+ public bool IsNativeInteger()
+ {
+ return false;
+ }
}
}
diff --git a/mdoc/Mono.Documentation/Updater/Formatters/AttributeFormatters/AttributeFormatter.cs b/mdoc/Mono.Documentation/Updater/Formatters/AttributeFormatters/AttributeFormatter.cs
index b8076d73..9bb23667 100644
--- a/mdoc/Mono.Documentation/Updater/Formatters/AttributeFormatters/AttributeFormatter.cs
+++ b/mdoc/Mono.Documentation/Updater/Formatters/AttributeFormatters/AttributeFormatter.cs
@@ -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?
diff --git a/mdoc/Mono.Documentation/Updater/Formatters/CSharpFullMemberFormatter.cs b/mdoc/Mono.Documentation/Updater/Formatters/CSharpFullMemberFormatter.cs
index 3a36a5e7..06368855 100644
--- a/mdoc/Mono.Documentation/Updater/Formatters/CSharpFullMemberFormatter.cs
+++ b/mdoc/Mono.Documentation/Updater/Formatters/CSharpFullMemberFormatter.cs
@@ -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)
{
@@ -152,7 +163,7 @@ namespace Mono.Documentation.Updater.Formatters
genArgTypeList.Add (underlyingTypeName);
}
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 (string.Join (", ", genArgList));
buf.Append (")");
return buf;
}
diff --git a/mdoc/Mono.Documentation/Updater/IAttributeParserContext.cs b/mdoc/Mono.Documentation/Updater/IAttributeParserContext.cs
index 471c661b..21feede9 100644
--- a/mdoc/Mono.Documentation/Updater/IAttributeParserContext.cs
+++ b/mdoc/Mono.Documentation/Updater/IAttributeParserContext.cs
@@ -6,5 +6,6 @@
bool IsDynamic();
bool IsNullable();
string GetTupleElementName();
+ bool IsNativeInteger();
}
}
diff --git a/mdoc/mdoc.Test/FormatterTests.cs b/mdoc/mdoc.Test/FormatterTests.cs
index fd987dec..b39d10c4 100644
--- a/mdoc/mdoc.Test/FormatterTests.cs
+++ b/mdoc/mdoc.Test/FormatterTests.cs
@@ -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]
@@ -425,7 +425,7 @@ namespace mdoc.Test
{
var type = GetType(typeof(SampleClasses.TupleNamesTestClass<,>));
var typeSignature = formatter.GetDeclaration(type);
- Assert.AreEqual("public class TupleNamesTestClass<T1,T2> : IComparable<(T1,T2)>", typeSignature);
+ Assert.AreEqual("public class TupleNamesTestClass<T1,T2> : IComparable<(T1, T2)>", typeSignature);
}
[Test]
@@ -433,7 +433,7 @@ namespace mdoc.Test
{
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);
+ Assert.AreEqual("public (int a, int b) TuplePropertyType { get; }", propertySignature);
}
[Test]
@@ -441,11 +441,11 @@ namespace mdoc.Test
{
var field = GetField(GetType(typeof(SampleClasses.TupleNamesTestClass<,>)), "TupleField");
var fieldSignature = formatter.GetDeclaration(field);
- Assert.AreEqual("public (int a,int b,int c) TupleField;", fieldSignature);
+ 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);")]
+ [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);
@@ -464,6 +464,25 @@ namespace mdoc.Test
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) {
diff --git a/mdoc/mdoc.Test/MDocUpdaterTests.cs b/mdoc/mdoc.Test/MDocUpdaterTests.cs
index 4e4a117c..6924df61 100644
--- a/mdoc/mdoc.Test/MDocUpdaterTests.cs
+++ b/mdoc/mdoc.Test/MDocUpdaterTests.cs
@@ -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;
@@ -32,6 +30,16 @@ namespace mdoc.Test
}
[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()
{
var method = GetMethod(typeof(Cpp.GenericBase<>), "BaseMethod2");
diff --git a/mdoc/mdoc.Test/NullableReferenceTypesTests.cs b/mdoc/mdoc.Test/NullableReferenceTypesTests.cs
index 5a166f47..f6cc3b40 100644
--- a/mdoc/mdoc.Test/NullableReferenceTypesTests.cs
+++ b/mdoc/mdoc.Test/NullableReferenceTypesTests.cs
@@ -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")]
diff --git a/mdoc/mdoc.Test/SampleClasses/NativeIntClass.cs b/mdoc/mdoc.Test/SampleClasses/NativeIntClass.cs
new file mode 100644
index 00000000..19fed899
--- /dev/null
+++ b/mdoc/mdoc.Test/SampleClasses/NativeIntClass.cs
@@ -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>
+ {
+
+ }
+} \ No newline at end of file