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

github.com/mono/cecil.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/rocks
diff options
context:
space:
mode:
authorMichael Jin <v-michaeljin@microsoft.com>2022-01-13 03:03:59 +0300
committerGitHub <noreply@github.com>2022-01-13 03:03:59 +0300
commit5f69faa7be1e10c8f6bc3c3b31cb4a63532496b8 (patch)
treeb925a5d28755119bcb262692e61a12e2352b3c19 /rocks
parenta0a6ce41c0e5292413ca33dcb76d514e608d21e5 (diff)
Add support for generating the method and generic method comment signature with nested types (#801)
* Add support for generating the method and generic method comment signature with nested types from Xiao Luo * Use type.GenericParameters.Count instead of custom method
Diffstat (limited to 'rocks')
-rw-r--r--rocks/Mono.Cecil.Rocks/DocCommentId.cs220
-rw-r--r--rocks/Test/Mono.Cecil.Tests/DocCommentIdTests.cs242
2 files changed, 321 insertions, 141 deletions
diff --git a/rocks/Mono.Cecil.Rocks/DocCommentId.cs b/rocks/Mono.Cecil.Rocks/DocCommentId.cs
index da74bed..8af12dd 100644
--- a/rocks/Mono.Cecil.Rocks/DocCommentId.cs
+++ b/rocks/Mono.Cecil.Rocks/DocCommentId.cs
@@ -10,16 +10,18 @@
using System;
using System.Collections.Generic;
+using System.Linq;
using System.Text;
namespace Mono.Cecil.Rocks {
- public class DocCommentId
- {
+ public class DocCommentId {
+ IMemberDefinition commentMember;
StringBuilder id;
- DocCommentId ()
+ DocCommentId (IMemberDefinition member)
{
+ commentMember = member;
id = new StringBuilder ();
}
@@ -87,54 +89,66 @@ namespace Mono.Cecil.Rocks {
void WriteTypeSignature (TypeReference type)
{
- switch (type.MetadataType)
- {
- case MetadataType.Array:
- WriteArrayTypeSignature ((ArrayType) type);
- break;
- case MetadataType.ByReference:
- WriteTypeSignature (((ByReferenceType) type).ElementType);
- id.Append ('@');
- break;
- case MetadataType.FunctionPointer:
- WriteFunctionPointerTypeSignature ((FunctionPointerType) type);
- break;
- case MetadataType.GenericInstance:
- WriteGenericInstanceTypeSignature ((GenericInstanceType) type);
- break;
- case MetadataType.Var:
+ switch (type.MetadataType) {
+ case MetadataType.Array:
+ WriteArrayTypeSignature ((ArrayType)type);
+ break;
+ case MetadataType.ByReference:
+ WriteTypeSignature (((ByReferenceType)type).ElementType);
+ id.Append ('@');
+ break;
+ case MetadataType.FunctionPointer:
+ WriteFunctionPointerTypeSignature ((FunctionPointerType)type);
+ break;
+ case MetadataType.GenericInstance:
+ WriteGenericInstanceTypeSignature ((GenericInstanceType)type);
+ break;
+ case MetadataType.Var:
+ if (IsGenericMethodTypeParameter (type))
id.Append ('`');
- id.Append (((GenericParameter) type).Position);
- break;
- case MetadataType.MVar:
- id.Append ('`').Append ('`');
- id.Append (((GenericParameter) type).Position);
- break;
- case MetadataType.OptionalModifier:
- WriteModiferTypeSignature ((OptionalModifierType) type, '!');
- break;
- case MetadataType.RequiredModifier:
- WriteModiferTypeSignature ((RequiredModifierType) type, '|');
- break;
- case MetadataType.Pointer:
- WriteTypeSignature (((PointerType) type).ElementType);
- id.Append ('*');
- break;
- default:
- WriteTypeFullName (type);
- break;
+ id.Append ('`');
+ id.Append (((GenericParameter)type).Position);
+ break;
+ case MetadataType.MVar:
+ id.Append ('`').Append ('`');
+ id.Append (((GenericParameter)type).Position);
+ break;
+ case MetadataType.OptionalModifier:
+ WriteModiferTypeSignature ((OptionalModifierType)type, '!');
+ break;
+ case MetadataType.RequiredModifier:
+ WriteModiferTypeSignature ((RequiredModifierType)type, '|');
+ break;
+ case MetadataType.Pointer:
+ WriteTypeSignature (((PointerType)type).ElementType);
+ id.Append ('*');
+ break;
+ default:
+ WriteTypeFullName (type);
+ break;
}
}
+ bool IsGenericMethodTypeParameter (TypeReference type)
+ {
+ if (commentMember is MethodDefinition methodDefinition && type is GenericParameter genericParameter)
+ return methodDefinition.GenericParameters.Any (i => i.Name == genericParameter.Name);
+
+ return false;
+ }
+
void WriteGenericInstanceTypeSignature (GenericInstanceType type)
{
if (type.ElementType.IsTypeSpecification ())
throw new NotSupportedException ();
- WriteTypeFullName (type.ElementType, stripGenericArity: true);
- id.Append ('{');
- WriteList (type.GenericArguments, WriteTypeSignature);
- id.Append ('}');
+ GenericTypeOptions options = new GenericTypeOptions {
+ IsArgument = true,
+ IsNestedType = type.IsNested,
+ Arguments = type.GenericArguments
+ };
+
+ WriteTypeFullName (type.ElementType, options);
}
void WriteList<T> (IList<T> list, Action<T> action)
@@ -197,10 +211,15 @@ namespace Mono.Cecil.Rocks {
WriteItemName (member.Name);
}
- void WriteTypeFullName (TypeReference type, bool stripGenericArity = false)
+ void WriteTypeFullName (TypeReference type)
+ {
+ WriteTypeFullName (type, GenericTypeOptions.Empty ());
+ }
+
+ void WriteTypeFullName (TypeReference type, GenericTypeOptions options)
{
if (type.DeclaringType != null) {
- WriteTypeFullName (type.DeclaringType);
+ WriteTypeFullName (type.DeclaringType, options);
id.Append ('.');
}
@@ -211,18 +230,69 @@ namespace Mono.Cecil.Rocks {
var name = type.Name;
- if (stripGenericArity) {
+ if (options.IsArgument) {
var index = name.LastIndexOf ('`');
if (index > 0)
name = name.Substring (0, index);
}
id.Append (name);
+
+ WriteGenericTypeParameters (type, options);
+ }
+
+ void WriteGenericTypeParameters (TypeReference type, GenericTypeOptions options)
+ {
+ if (options.IsArgument && IsGenericType (type)) {
+ id.Append ('{');
+ WriteList (GetGenericTypeArguments (type, options), WriteTypeSignature);
+ id.Append ('}');
+ }
+ }
+
+ static bool IsGenericType (TypeReference type)
+ {
+ // When the type is a nested type and that is defined in a generic class,
+ // the nested type will have generic parameters but sometimes that is not a generic type.
+ if (type.HasGenericParameters) {
+ var name = string.Empty;
+ var index = type.Name.LastIndexOf ('`');
+ if (index >= 0)
+ name = type.Name.Substring (0, index);
+
+ return type.Name.LastIndexOf ('`') == name.Length;
+ }
+
+ return false;
}
+ IList<TypeReference> GetGenericTypeArguments (TypeReference type, GenericTypeOptions options)
+ {
+ if (options.IsNestedType) {
+ var typeParameterCount = type.GenericParameters.Count;
+ var typeGenericArguments = options.Arguments.Skip (options.ArgumentIndex).Take (typeParameterCount).ToList ();
+
+ options.ArgumentIndex += typeParameterCount;
+
+ return typeGenericArguments;
+ }
+
+ return options.Arguments;
+ }
+
+ //int GetGenericTypeParameterCount (TypeReference type)
+ //{
+ // var returnValue = 0;
+ // var index = type.Name.LastIndexOf ('`');
+ // if (index >= 0)
+ // returnValue = int.Parse (type.Name.Substring (index + 1));
+
+ // return returnValue;
+ //}
+
void WriteItemName (string name)
{
- id.Append (name.Replace ('.', '#').Replace('<', '{').Replace('>', '}'));
+ id.Append (name.Replace('.', '#').Replace('<', '{').Replace('>', '}'));
}
public override string ToString ()
@@ -235,30 +305,44 @@ namespace Mono.Cecil.Rocks {
if (member == null)
throw new ArgumentNullException ("member");
- var documentId = new DocCommentId ();
-
- switch (member.MetadataToken.TokenType)
- {
- case TokenType.Field:
- documentId.WriteField ((FieldDefinition) member);
- break;
- case TokenType.Method:
- documentId.WriteMethod ((MethodDefinition) member);
- break;
- case TokenType.TypeDef:
- documentId.WriteType ((TypeDefinition) member);
- break;
- case TokenType.Event:
- documentId.WriteEvent ((EventDefinition) member);
- break;
- case TokenType.Property:
- documentId.WriteProperty ((PropertyDefinition) member);
- break;
- default:
- throw new NotSupportedException (member.FullName);
+ var documentId = new DocCommentId (member);
+
+ switch (member.MetadataToken.TokenType) {
+ case TokenType.Field:
+ documentId.WriteField ((FieldDefinition)member);
+ break;
+ case TokenType.Method:
+ documentId.WriteMethod ((MethodDefinition)member);
+ break;
+ case TokenType.TypeDef:
+ documentId.WriteType ((TypeDefinition)member);
+ break;
+ case TokenType.Event:
+ documentId.WriteEvent ((EventDefinition)member);
+ break;
+ case TokenType.Property:
+ documentId.WriteProperty ((PropertyDefinition)member);
+ break;
+ default:
+ throw new NotSupportedException (member.FullName);
}
return documentId.ToString ();
}
+
+ class GenericTypeOptions {
+ public bool IsArgument { get; set; }
+
+ public bool IsNestedType { get; set; }
+
+ public IList<TypeReference> Arguments { get; set; }
+
+ public int ArgumentIndex { get; set; }
+
+ public static GenericTypeOptions Empty ()
+ {
+ return new GenericTypeOptions ();
+ }
+ }
}
-}
+} \ No newline at end of file
diff --git a/rocks/Test/Mono.Cecil.Tests/DocCommentIdTests.cs b/rocks/Test/Mono.Cecil.Tests/DocCommentIdTests.cs
index 244d5ae..8cfc828 100644
--- a/rocks/Test/Mono.Cecil.Tests/DocCommentIdTests.cs
+++ b/rocks/Test/Mono.Cecil.Tests/DocCommentIdTests.cs
@@ -6,116 +6,181 @@ using NUnit.Framework;
using Mono.Cecil.Rocks;
-namespace N
-{
+namespace N {
- /// <summary>
- /// ID string generated is "T:N.X".
- /// </summary>
- public class X : IX<KVP<string, int>>
- {
- /// <summary>
- /// ID string generated is "M:N.X.#ctor".
- /// </summary>
- public X() { }
+ /// <summary>
+ /// ID string generated is "T:N.X".
+ /// </summary>
+ public class X : IX<KVP<string, int>> {
+ /// <summary>
+ /// ID string generated is "M:N.X.#ctor".
+ /// </summary>
+ public X () { }
- /// <summary>
- /// ID string generated is "M:N.X.#ctor(System.Int32)".
- /// </summary>
- /// <param name="i">Describe parameter.</param>
- public X(int i) { }
+ /// <summary>
+ /// ID string generated is "M:N.X.#ctor(System.Int32)".
+ /// </summary>
+ /// <param name="i">Describe parameter.</param>
+ public X (int i) { }
- /// <summary>
- /// ID string generated is "F:N.X.q".
- /// </summary>
- public string q;
+ /// <summary>
+ /// ID string generated is "F:N.X.q".
+ /// </summary>
+ public string q;
- /// <summary>
- /// ID string generated is "F:N.X.PI".
- /// </summary>
- public const double PI = 3.14;
+ /// <summary>
+ /// ID string generated is "F:N.X.PI".
+ /// </summary>
+ public const double PI = 3.14;
- /// <summary>
- /// ID string generated is "M:N.X.f".
- /// </summary>
- public int f() { return 1; }
+ /// <summary>
+ /// ID string generated is "M:N.X.f".
+ /// </summary>
+ public int f () { return 1; }
- /// <summary>
- /// ID string generated is "M:N.X.bb(System.String,System.Int32@)".
- /// </summary>
- public int bb(string s, ref int y) { return 1; }
+ /// <summary>
+ /// ID string generated is "M:N.X.bb(System.String,System.Int32@)".
+ /// </summary>
+ public int bb (string s, ref int y) { return 1; }
- /// <summary>
- /// ID string generated is "M:N.X.gg(System.Int16[],System.Int32[0:,0:])".
- /// </summary>
- public int gg(short[] array1, int[,] array) { return 0; }
+ /// <summary>
+ /// ID string generated is "M:N.X.gg(System.Int16[],System.Int32[0:,0:])".
+ /// </summary>
+ public int gg (short [] array1, int [,] array) { return 0; }
- /// <summary>
- /// ID string generated is "M:N.X.op_Addition(N.X,N.X)".
- /// </summary>
- public static X operator +(X x, X xx) { return x; }
+ /// <summary>
+ /// ID string generated is "M:N.X.op_Addition(N.X,N.X)".
+ /// </summary>
+ public static X operator + (X x, X xx) { return x; }
- /// <summary>
- /// ID string generated is "P:N.X.prop".
- /// </summary>
- public int prop { get { return 1; } set { } }
+ /// <summary>
+ /// ID string generated is "P:N.X.prop".
+ /// </summary>
+ public int prop { get { return 1; } set { } }
- /// <summary>
- /// ID string generated is "E:N.X.d".
- /// </summary>
+ /// <summary>
+ /// ID string generated is "E:N.X.d".
+ /// </summary>
#pragma warning disable 67
- public event D d;
+ public event D d;
#pragma warning restore 67
/// <summary>
/// ID string generated is "P:N.X.Item(System.String)".
/// </summary>
- public int this[string s] { get { return 1; } }
+ public int this [string s] { get { return 1; } }
- /// <summary>
- /// ID string generated is "T:N.X.Nested".
- /// </summary>
- public class Nested { }
+ /// <summary>
+ /// ID string generated is "T:N.X.Nested".
+ /// </summary>
+ public class Nested { }
- /// <summary>
- /// ID string generated is "T:N.X.D".
- /// </summary>
- public delegate void D(int i);
+ /// <summary>
+ /// ID string generated is "T:N.X.D".
+ /// </summary>
+ public delegate void D (int i);
- /// <summary>
- /// ID string generated is "M:N.X.op_Explicit(N.X)~System.Int32".
- /// </summary>
- public static explicit operator int(X x) { return 1; }
+ /// <summary>
+ /// ID string generated is "M:N.X.op_Explicit(N.X)~System.Int32".
+ /// </summary>
+ public static explicit operator int (X x) { return 1; }
- public static void Linq (IEnumerable<string> enumerable, Func<string> selector)
- {
- }
+ public static void Linq (IEnumerable<string> enumerable, Func<string> selector)
+ {
+ }
- /// <summary>
+ /// <summary>
/// ID string generated is "M:N.X.N#IX{N#KVP{System#String,System#Int32}}#IXA(N.KVP{System.String,System.Int32})"
- /// </summary>
- void IX<KVP<string, int>>.IXA (KVP<string, int> k) { }
- }
+ /// </summary>
+ void IX<KVP<string, int>>.IXA (KVP<string, int> k) { }
+ }
- public interface IX<K>
- {
+ public interface IX<K> {
void IXA (K k);
}
public class KVP<K, T> { }
+
+ public class GenericMethod {
+ /// <summary>
+ /// ID string generated is "M:N.GenericMethod.WithNestedType``1(N.GenericType{``0}.NestedType)".
+ /// </summary>
+ public void WithNestedType<T> (GenericType<T>.NestedType nestedType) { }
+
+
+ /// <summary>
+ /// ID string generated is "M:N.GenericMethod.WithIntOfNestedType``1(N.GenericType{System.Int32}.NestedType)".
+ /// </summary>
+ public void WithIntOfNestedType<T> (GenericType<int>.NestedType nestedType) { }
+
+
+ /// <summary>
+ /// ID string generated is "M:N.GenericMethod.WithNestedGenericType``1(N.GenericType{``0}.NestedGenericType{``0}.NestedType)".
+ /// </summary>
+ public void WithNestedGenericType<T> (GenericType<T>.NestedGenericType<T>.NestedType nestedType) { }
+
+
+ /// <summary>
+ /// ID string generated is "M:N.GenericMethod.WithIntOfNestedGenericType``1(N.GenericType{System.Int32}.NestedGenericType{System.Int32}.NestedType)".
+ /// </summary>
+ public void WithIntOfNestedGenericType<T> (GenericType<int>.NestedGenericType<int>.NestedType nestedType) { }
+
+
+ /// <summary>
+ /// ID string generated is "M:N.GenericMethod.WithMultipleTypeParameterAndNestedGenericType``2(N.GenericType{``0}.NestedGenericType{``1}.NestedType)".
+ /// </summary>
+ public void WithMultipleTypeParameterAndNestedGenericType<T1, T2> (GenericType<T1>.NestedGenericType<T2>.NestedType nestedType) { }
+
+
+ /// <summary>
+ /// ID string generated is "M:N.GenericMethod.WithMultipleTypeParameterAndIntOfNestedGenericType``2(N.GenericType{System.Int32}.NestedGenericType{System.Int32}.NestedType)".
+ /// </summary>
+ public void WithMultipleTypeParameterAndIntOfNestedGenericType<T1, T2> (GenericType<int>.NestedGenericType<int>.NestedType nestedType) { }
+ }
+
+ public class GenericType<T> {
+ public class NestedType { }
+
+ public class NestedGenericType<TNested> {
+ public class NestedType { }
+
+ /// <summary>
+ /// ID string generated is "M:N.GenericType`1.NestedGenericType`1.WithTypeParameterOfGenericMethod``1(System.Collections.Generic.List{``0})"
+ /// </summary>
+ public void WithTypeParameterOfGenericMethod<TMethod> (List<TMethod> list) { }
+
+
+ /// <summary>
+ /// ID string generated is "M:N.GenericType`1.NestedGenericType`1.WithTypeParameterOfGenericType(System.Collections.Generic.Dictionary{`0,`1})"
+ /// </summary>
+ public void WithTypeParameterOfGenericType (Dictionary<T, TNested> dict) { }
+
+
+ /// <summary>
+ /// ID string generated is "M:N.GenericType`1.NestedGenericType`1.WithTypeParameterOfGenericType``1(System.Collections.Generic.List{`1})"
+ /// </summary>
+ public void WithTypeParameterOfNestedGenericType<TMethod> (List<TNested> list) { }
+
+
+ /// <summary>
+ /// ID string generated is "M:N.GenericType`1.NestedGenericType`1.WithTypeParameterOfGenericTypeAndGenericMethod``1(System.Collections.Generic.Dictionary{`1,``0})"
+ /// </summary>
+ public void WithTypeParameterOfGenericTypeAndGenericMethod<TMethod> (Dictionary<TNested, TMethod> dict) { }
+ }
+ }
}
namespace Mono.Cecil.Tests {
@@ -182,7 +247,7 @@ namespace Mono.Cecil.Tests {
AssertDocumentID ("M:N.X.bb(System.String,System.Int32@)", method);
}
-
+
[Test]
public void MethodWithArrayParameters ()
{
@@ -192,6 +257,32 @@ namespace Mono.Cecil.Tests {
AssertDocumentID ("M:N.X.gg(System.Int16[],System.Int32[0:,0:])", method);
}
+ [TestCase ("WithNestedType", "WithNestedType``1(N.GenericType{``0}.NestedType)")]
+ [TestCase ("WithIntOfNestedType", "WithIntOfNestedType``1(N.GenericType{System.Int32}.NestedType)")]
+ [TestCase ("WithNestedGenericType", "WithNestedGenericType``1(N.GenericType{``0}.NestedGenericType{``0}.NestedType)")]
+ [TestCase ("WithIntOfNestedGenericType", "WithIntOfNestedGenericType``1(N.GenericType{System.Int32}.NestedGenericType{System.Int32}.NestedType)")]
+ [TestCase ("WithMultipleTypeParameterAndNestedGenericType", "WithMultipleTypeParameterAndNestedGenericType``2(N.GenericType{``0}.NestedGenericType{``1}.NestedType)")]
+ [TestCase ("WithMultipleTypeParameterAndIntOfNestedGenericType", "WithMultipleTypeParameterAndIntOfNestedGenericType``2(N.GenericType{System.Int32}.NestedGenericType{System.Int32}.NestedType)")]
+ public void GenericMethodWithNestedTypeParameters (string methodName, string docCommentId)
+ {
+ var type = GetTestType (typeof (N.GenericMethod));
+ var method = type.Methods.Single (m => m.Name == methodName);
+
+ AssertDocumentID ($"M:N.GenericMethod.{docCommentId}", method);
+ }
+
+ [TestCase ("WithTypeParameterOfGenericMethod", "WithTypeParameterOfGenericMethod``1(System.Collections.Generic.List{``0})")]
+ [TestCase ("WithTypeParameterOfGenericType", "WithTypeParameterOfGenericType(System.Collections.Generic.Dictionary{`0,`1})")]
+ [TestCase ("WithTypeParameterOfNestedGenericType", "WithTypeParameterOfNestedGenericType``1(System.Collections.Generic.List{`1})")]
+ [TestCase ("WithTypeParameterOfGenericTypeAndGenericMethod", "WithTypeParameterOfGenericTypeAndGenericMethod``1(System.Collections.Generic.Dictionary{`1,``0})")]
+ public void GenericTypeWithTypeParameters (string methodName, string docCommentId)
+ {
+ var type = GetTestType (typeof (N.GenericType<>.NestedGenericType<>));
+ var method = type.Methods.Single (m => m.Name == methodName);
+
+ AssertDocumentID ($"M:N.GenericType`1.NestedGenericType`1.{docCommentId}", method);
+ }
+
[Test]
public void OpAddition ()
{
@@ -268,7 +359,7 @@ namespace Mono.Cecil.Tests {
public void EII ()
{
var type = GetTestType ();
- var method = type.Methods.Where (m => m.Name.Contains("IXA")).First ();
+ var method = type.Methods.Where (m => m.Name.Contains ("IXA")).First ();
AssertDocumentID ("M:N.X.N#IX{N#KVP{System#String,System#Int32}}#IXA(N.KVP{System.String,System.Int32})", method);
}
@@ -278,9 +369,14 @@ namespace Mono.Cecil.Tests {
return typeof (N.X).ToDefinition ();
}
+ TypeDefinition GetTestType (Type type)
+ {
+ return type.ToDefinition ();
+ }
+
static void AssertDocumentID (string docId, IMemberDefinition member)
{
Assert.AreEqual (docId, DocCommentId.GetDocCommentId (member));
}
}
-}
+} \ No newline at end of file