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:
Родитель
637f82100f
Коммит
c27c019e5a
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
Загрузка…
Ссылка в новой задаче