feat#550401: Support new .net language feature: tuple names (#618)

* Support new .net language feature: tuple names

* update test case

* update test case

* update

* updated

* update test case

* add debug info

* update

* Remove console log
This commit is contained in:
Min Huang 2022-03-08 09:28:57 +08:00 коммит произвёл GitHub
Родитель 637f82100f
Коммит c27c019e5a
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
7 изменённых файлов: 87 добавлений и 3 удалений

Просмотреть файл

@ -49,5 +49,6 @@ 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";
}
}

Просмотреть файл

@ -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,11 @@ namespace Mono.Documentation.Updater
{
private int nullableAttributeIndex;
private int dynamicAttributeIndex;
private int tupleNameAttributeIndex;
private ICustomAttributeProvider provider;
private ReadOnlyCollection<bool?> nullableAttributeFlags;
private ReadOnlyCollection<bool> dynamicAttributeFlags;
private string[] tupleElementNames;
private AttributeParserContext(ICustomAttributeProvider provider)
{
@ -20,6 +23,7 @@ namespace Mono.Documentation.Updater
ReadDynamicAttribute();
ReadNullableAttribute();
ReadTupleElementNames();
}
private bool ExistsNullableAttribute
@ -73,6 +77,11 @@ namespace Mono.Documentation.Updater
return false;
}
public string GetTupleElementName()
{
return (tupleElementNames == null || tupleNameAttributeIndex >= tupleElementNames.Length) ? null : tupleElementNames[tupleNameAttributeIndex++];
}
private void ReadDynamicAttribute()
{
DynamicTypeProvider dynamicTypeProvider = new DynamicTypeProvider(provider);
@ -88,5 +97,18 @@ namespace Mono.Documentation.Updater
NullableReferenceTypeProvider nullableReferenceTypeProvider = new NullableReferenceTypeProvider(provider);
nullableAttributeFlags = new ReadOnlyCollection<bool?>(nullableReferenceTypeProvider.GetNullableReferenceTypeFlags());
}
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();
}
}
}
}
}

Просмотреть файл

@ -26,5 +26,10 @@
{
return false;
}
public string GetTupleElementName()
{
return null;
}
}
}

Просмотреть файл

@ -137,7 +137,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 +149,11 @@ namespace Mono.Documentation.Updater.Formatters
}
var underlyingTypeName = GetTypeName (item, context, appendGeneric, useTypeProjection) + GetTypeNullableSymbol (item, isNullableType);
genArgList.Add (underlyingTypeName);
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 (")");
return buf;
}

Просмотреть файл

@ -5,5 +5,6 @@
void NextDynamicFlag();
bool IsDynamic();
bool IsNullable();
string GetTupleElementName();
}
}

Просмотреть файл

@ -420,6 +420,39 @@ 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);
}
#region Helper Methods
string RealTypeName(string name){
switch (name) {

Просмотреть файл

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