diff --git a/EventPipe.Test/SymbolCleanerTest.cs b/EventPipe.Test/SymbolCleanerTest.cs index ec86fde..5eb22f0 100644 --- a/EventPipe.Test/SymbolCleanerTest.cs +++ b/EventPipe.Test/SymbolCleanerTest.cs @@ -83,12 +83,12 @@ private static IEnumerable TestCaseSource() ExpectedResult = "Contoso.Cookies.CookieEntry.TryGet(T&, System.Exception&, int32, bool)", }; yield return new TestCaseData( - "System.Threading.Tasks.Task+DelayPromiseWithCancellation+<>c", - "<.ctor>b__1_0", - "instance void (class System.Object,value class System.Threading.CancellationToken)") + "System.Collections.Immutable.ImmutableDictionary`2[Contoso.Banners.Configuration.Inventory.Sources.InventoryAvailabilityKey,Contoso.Banners.Configuration.Inventory.Sources.AvailableBanner]", + "Wrap", + "class System.Collections.Immutable.ImmutableDictionary`2 (class System.Collections.Immutable.SortedInt32KeyNode`1>,class Comparers,int32)") { - ExpectedResult = "System.Threading.Tasks.Task+DelayPromiseWithCancellation+<>c.<.ctor>b__1_0(System.Object, System.Threading.CancellationToken)", - RunState = RunState.Ignored, + TestName = "Generic arguments using angle brackets and no tilde", + ExpectedResult = "System.Collections.Immutable.ImmutableDictionary.Wrap(System.Collections.Immutable.SortedInt32KeyNode>, Comparers, int32)", }; yield return new TestCaseData( "Sdk.Connection.GhostClientBase`2+d__42[System.__Canon,System.__Canon]", @@ -104,7 +104,8 @@ private static IEnumerable TestCaseSource() "instance void ()") { TestName = "Mix of T and specified type", - ExpectedResult = "Ghost.Core.ComponentMiddleware.Invoke()", + ExpectedResult = + "Ghost.Core.ComponentMiddleware.Invoke()", }; yield return new TestCaseData( "Ghost.Transports.Http.Common.Middlewares.HttpExceptionMiddleware", @@ -112,7 +113,8 @@ private static IEnumerable TestCaseSource() "instance class System.Threading.Tasks.Task`1 (class Ghost.Transports.Http.Contract.IHttpRequest,class Ghost.Transports.Http.Contract.IHttpResponse,value class System.Threading.CancellationToken)") { TestName = "Mix of class and struct arguments", - ExpectedResult = "Ghost.Transports.Http.Common.Middlewares.HttpExceptionMiddleware.Invoke(Ghost.Transports.Http.Contract.IHttpRequest, Ghost.Transports.Http.Contract.IHttpResponse, System.Threading.CancellationToken)", + ExpectedResult = + "Ghost.Transports.Http.Common.Middlewares.HttpExceptionMiddleware.Invoke(Ghost.Transports.Http.Contract.IHttpRequest, Ghost.Transports.Http.Contract.IHttpResponse, System.Threading.CancellationToken)", }; yield return new TestCaseData( "Program", @@ -128,7 +130,8 @@ private static IEnumerable TestCaseSource() "instance value class Contoso.API.Versatile.EnumerableVariant (class System.Collections.Generic.IEnumerable`1)") { TestName = "Generic argument", - ExpectedResult = "Contoso.API.Versatile.Functions.FlattenedFunction.Evaluate(System.Collections.Generic.IEnumerable)", + ExpectedResult = + "Contoso.API.Versatile.Functions.FlattenedFunction.Evaluate(System.Collections.Generic.IEnumerable)", }; yield return new TestCaseData( "Program", @@ -136,7 +139,8 @@ private static IEnumerable TestCaseSource() "instance int32 (value class System.ValueTuple`5)") { TestName = "Value tuple argument", - ExpectedResult = "Program.InstanceMethod(System.ValueTuple)", + ExpectedResult = + "Program.InstanceMethod(System.ValueTuple)", }; yield return new TestCaseData( "Program+d__3", @@ -162,14 +166,54 @@ private static IEnumerable TestCaseSource() TestName = "Local generic async method in generic async method", ExpectedResult = "Program.GenericInstanceMethodAsync.LocalGenericMethodAsync()", }; + yield return new TestCaseData( + "System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1+AsyncStateMachineBox`1[System.Threading.Tasks.VoidTaskResult,Contoso.ThirdPartyDemand.Bidding.Framework.DspSpecificCompositeStep+<>c__DisplayClass3_0+<g__OnDspState|0>d]", + "MoveNext", + "instance void (class System.Threading.Thread)") + { + TestName = "Lambda of local method", + ExpectedResult = "System.Runtime.CompilerServices.AsyncTaskMethodBuilder+AsyncStateMachineBox{}.Process.OnDspState>(System.Threading.Thread)", + }; + yield return new TestCaseData( + "System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1+AsyncStateMachineBox`1[System.Threading.Tasks.VoidTaskResult,JetBrains.TextControl.DocumentMarkup.GutterMarksBackendServices+<>c__DisplayClass3_0+<<-ctor>g__BeginCreateForTextControlIfAllowed|1>d]", + "MoveNext", + "instance void (class System.Threading.Thread)") + { + TestName = "Lambda of a local method in a constructor", + ExpectedResult = "System.Runtime.CompilerServices.AsyncTaskMethodBuilder+AsyncStateMachineBox{}.-ctor.BeginCreateForTextControlIfAllowed>(System.Threading.Thread)", + }; + yield return new TestCaseData( + "System.Threading.Tasks.Task+DelayPromiseWithCancellation+<>c", + "<.ctor>b__1_0", + "instance void (class System.Object,value class System.Threading.CancellationToken)") + { + TestName = "Lambda in constructor", + ExpectedResult = + "System.Threading.Tasks.Task+DelayPromiseWithCancellation.()=>{}.<.ctor>b__1_0(System.Object, System.Threading.CancellationToken)", + }; + yield return new TestCaseData( + "System.Net.Http.HttpConnectionPool+<>c", + "b__77_0", + "instance void (value class System.ValueTuple`2>)") + { + TestName = "Short lambda notation", + ExpectedResult = "System.Net.Http.HttpConnectionPool.()=>{}.b__77_0(System.ValueTuple>)", + }; + yield return new TestCaseData( + "System.Threading.Tasks.ValueTask`1+ValueTaskSourceAsTask+<>c[System.Int32]", + "<.cctor>b__4_0", + "instance void (class System.Object)") + { + TestName = "Generic lambda", + ExpectedResult = "System.Threading.Tasks.ValueTask+ValueTaskSourceAsTask.()=>{}.<.cctor>b__4_0(System.Object)", + }; yield return new TestCaseData( "Program", "<.ctor>g__LocalMethod|1_1", "void ()") { TestName = "Local method in constructor", - ExpectedResult = "Program..ctor.LocalMethod", - RunState = RunState.Ignored, + ExpectedResult = "Program.<.ctor>g__LocalMethod|1_1()", }; yield return new TestCaseData( "Program", @@ -177,8 +221,7 @@ private static IEnumerable TestCaseSource() "void ()") { TestName = "Local method", - ExpectedResult = "Program.InstanceMethod.LocalMethod", - RunState = RunState.Ignored, + ExpectedResult = "Program.g__LocalMethod|2_1()", }; yield return new TestCaseData( "Program+d__4", @@ -188,14 +231,21 @@ private static IEnumerable TestCaseSource() TestName = "Enumerable Method", ExpectedResult = "Program.MyEnumerableMethod()", }; + yield return new TestCaseData( + "Microsoft.EntityFrameworkCore.Query.Internal.SplitQueryingEnumerable`1+AsyncEnumerator+<>c[System.Int32]", + "b__19_0", + "instance class System.Threading.Tasks.Task`1 (class Microsoft.EntityFrameworkCore.DbContext,class AsyncEnumerator,value class System.Threading.CancellationToken)") + { + TestName = "Async enumerable method", + ExpectedResult = "Microsoft.EntityFrameworkCore.Query.Internal.SplitQueryingEnumerable+AsyncEnumerator.()=>{}.b__19_0(Microsoft.EntityFrameworkCore.DbContext, AsyncEnumerator, System.Threading.CancellationToken)", + }; yield return new TestCaseData( "Program+<>c", "
b__7_0", - "Signature=instance void (int32,class System.Object)") + "instance void (int32,class System.Object)") { TestName = "Lambda", - ExpectedResult = "Program.Main.lambda(int, System.Object)", - RunState = RunState.Ignored, + ExpectedResult = "Program.()=>{}.
b__7_0(int32, System.Object)", }; yield return new TestCaseData( "Contoso.CookiesUpdater.PublisherCookiesUpdater+<>c__DisplayClass10_0+<b__0>d", @@ -203,7 +253,7 @@ private static IEnumerable TestCaseSource() "instance void ()") { TestName = "Async lambda", - ExpectedResult = "Contoso.CookiesUpdater.PublisherCookiesUpdater.OnBidRequest()", + ExpectedResult = "Contoso.CookiesUpdater.PublisherCookiesUpdater.()=>{}.OnBidRequest()", }; yield return new TestCaseData( "Program+<>c__DisplayClass7_0", @@ -211,7 +261,7 @@ private static IEnumerable TestCaseSource() "instance void (class System.String)") { TestName = "Closure", - ExpectedResult = "Program.Main.lambda(System.String)", + ExpectedResult = "Program.()=>{}.
b__1(System.String)", RunState = RunState.Ignored, }; } diff --git a/EventPipe/SymbolCleaner.cs b/EventPipe/SymbolCleaner.cs index 08efe8c..ca7275f 100644 --- a/EventPipe/SymbolCleaner.cs +++ b/EventPipe/SymbolCleaner.cs @@ -35,6 +35,7 @@ public static string Clean(string ns, string name, string signature) private static int AppendCleanedType(StringBuilder sb, ReadOnlySpan str) { int typeNameStartIndex = -1; + bool subType = false; int i; for (i = 0; i < str.Length; i += 1) { @@ -57,14 +58,7 @@ private static int AppendCleanedType(StringBuilder sb, ReadOnlySpan str) continue; } - if (str[i] == '<') - { - i += AppendCleanedGeneratedType(sb, str[i..]); - i -= 1; - continue; - } - - if (str[i] is '`' or '[') + if (str[i] is '`' or '[' or '<') { if (typeNameStartIndex != -1) { @@ -72,7 +66,16 @@ private static int AppendCleanedType(StringBuilder sb, ReadOnlySpan str) typeNameStartIndex = -1; } - i += AppendTypeArguments(sb, str[i..], hasTildeHeader: str[i] == '`'); + // Some subclass names can contain '<', in that case it's not the start of type arguments. + if (str[i] == '<' && subType) + { + i += AppendCleanedGeneratedType(sb, str[i..]); + } + else + { + i += AppendTypeArguments(sb, str[i..], hasTildeHeader: str[i] == '`'); + } + i -= 1; continue; } @@ -86,6 +89,7 @@ private static int AppendCleanedType(StringBuilder sb, ReadOnlySpan str) } sb.Append('+'); + subType = true; continue; } @@ -180,10 +184,23 @@ private static int AppendCleanedGeneratedType(StringBuilder sb, ReadOnlySpang__ sb.Append('.'); continue; } if (str[i + 1] == 'c') { - if (i + 2 >= str.Length) + sb.Append("()=>{}"); + if (i + 2 == str.Length || str[i + 2] != '_') { - return str.Length; + i += 2; // Skips >c + continue; } + sb.Append('.'); i += 16; // Skips >c__DisplayClass i += SkipDigits(str[i..]); i += 1; // Skips _ @@ -225,16 +245,21 @@ private static int AppendCleanedGeneratedType(StringBuilder sb, ReadOnlySpand return i; } sb.Append(str[i]); + i += 1; } - return str.Length; + return i; static int SkipDigits(ReadOnlySpan s) {