diff --git a/Ben.Demystifier.sln b/Ben.Demystifier.sln
deleted file mode 100644
index 0b7c702..0000000
--- a/Ben.Demystifier.sln
+++ /dev/null
@@ -1,71 +0,0 @@
-
-Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 15
-VisualStudioVersion = 15.0.27019.1
-MinimumVisualStudioVersion = 10.0.40219.1
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{A2FCCAAC-BE90-4F7E-B95F-A72D46DDD6B3}"
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{59CA6310-4AA5-4093-95D4-472B94DC0CD4}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ben.Demystifier", "src\Ben.Demystifier\Ben.Demystifier.csproj", "{5410A056-89AB-4912-BD1E-A63616AD91D0}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ben.Demystifier.Test", "test\Ben.Demystifier.Test\Ben.Demystifier.Test.csproj", "{B9E150B0-AEEB-4D98-8BE1-92C1296699A2}"
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "sample", "sample", "{455921D3-DD54-4355-85CF-F4009DF2AB70}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StackTrace", "sample\StackTrace\StackTrace.csproj", "{E161FC12-53C2-47CD-A5FC-3684B86723A9}"
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{5937ACDF-0059-488E-9604-D84689C72933}"
- ProjectSection(SolutionItems) = preProject
- appveyor.yml = appveyor.yml
- build.ps1 = build.ps1
- Directory.Build.props = Directory.Build.props
- README.md = README.md
- version.json = version.json
- EndProjectSection
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ben.Demystifier.Benchmarks", "test\Ben.Demystifier.Benchmarks\Ben.Demystifier.Benchmarks.csproj", "{EF5557DF-C48E-4999-846C-D99A92E86373}"
-EndProject
-Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "FSharpStackTrace", "sample\FSharpStackTrace\FSharpStackTrace.fsproj", "{D6B779D2-A678-47CC-A2F9-A312292EA7A2}"
-EndProject
-Global
- GlobalSection(SolutionConfigurationPlatforms) = preSolution
- Debug|Any CPU = Debug|Any CPU
- Release|Any CPU = Release|Any CPU
- EndGlobalSection
- GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {5410A056-89AB-4912-BD1E-A63616AD91D0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {5410A056-89AB-4912-BD1E-A63616AD91D0}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {5410A056-89AB-4912-BD1E-A63616AD91D0}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {5410A056-89AB-4912-BD1E-A63616AD91D0}.Release|Any CPU.Build.0 = Release|Any CPU
- {B9E150B0-AEEB-4D98-8BE1-92C1296699A2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {B9E150B0-AEEB-4D98-8BE1-92C1296699A2}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {B9E150B0-AEEB-4D98-8BE1-92C1296699A2}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {B9E150B0-AEEB-4D98-8BE1-92C1296699A2}.Release|Any CPU.Build.0 = Release|Any CPU
- {E161FC12-53C2-47CD-A5FC-3684B86723A9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {E161FC12-53C2-47CD-A5FC-3684B86723A9}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {E161FC12-53C2-47CD-A5FC-3684B86723A9}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {E161FC12-53C2-47CD-A5FC-3684B86723A9}.Release|Any CPU.Build.0 = Release|Any CPU
- {EF5557DF-C48E-4999-846C-D99A92E86373}.Debug|Any CPU.ActiveCfg = Release|Any CPU
- {EF5557DF-C48E-4999-846C-D99A92E86373}.Debug|Any CPU.Build.0 = Release|Any CPU
- {EF5557DF-C48E-4999-846C-D99A92E86373}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {EF5557DF-C48E-4999-846C-D99A92E86373}.Release|Any CPU.Build.0 = Release|Any CPU
- {D6B779D2-A678-47CC-A2F9-A312292EA7A2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {D6B779D2-A678-47CC-A2F9-A312292EA7A2}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {D6B779D2-A678-47CC-A2F9-A312292EA7A2}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {D6B779D2-A678-47CC-A2F9-A312292EA7A2}.Release|Any CPU.Build.0 = Release|Any CPU
- EndGlobalSection
- GlobalSection(SolutionProperties) = preSolution
- HideSolutionNode = FALSE
- EndGlobalSection
- GlobalSection(NestedProjects) = preSolution
- {5410A056-89AB-4912-BD1E-A63616AD91D0} = {A2FCCAAC-BE90-4F7E-B95F-A72D46DDD6B3}
- {B9E150B0-AEEB-4D98-8BE1-92C1296699A2} = {59CA6310-4AA5-4093-95D4-472B94DC0CD4}
- {E161FC12-53C2-47CD-A5FC-3684B86723A9} = {455921D3-DD54-4355-85CF-F4009DF2AB70}
- {EF5557DF-C48E-4999-846C-D99A92E86373} = {59CA6310-4AA5-4093-95D4-472B94DC0CD4}
- {D6B779D2-A678-47CC-A2F9-A312292EA7A2} = {455921D3-DD54-4355-85CF-F4009DF2AB70}
- EndGlobalSection
- GlobalSection(ExtensibilityGlobals) = postSolution
- SolutionGuid = {841B7D5F-E810-4F94-A529-002C7E075216}
- EndGlobalSection
-EndGlobal
diff --git a/src/Ben.Demystifier/Ben.Demystifier.csproj b/src/Ben.Demystifier/Ben.Demystifier.csproj
index ebc33c9..9a09d92 100644
--- a/src/Ben.Demystifier/Ben.Demystifier.csproj
+++ b/src/Ben.Demystifier/Ben.Demystifier.csproj
@@ -1,16 +1,16 @@
-
- embedded
- true
- enable
- true
- netstandard2.1;netstandard2.0;net45;net6.0
-
+
+ embedded
+ true
+ enable
+ true
+ net6.0
+
-
-
-
-
+
+
+
+
diff --git a/src/Ben.Demystifier/EnhancedStackFrame.cs b/src/Ben.Demystifier/EnhancedStackFrame.cs
index f54ffdb..fa8609a 100644
--- a/src/Ben.Demystifier/EnhancedStackFrame.cs
+++ b/src/Ben.Demystifier/EnhancedStackFrame.cs
@@ -1,93 +1,84 @@
// Copyright (c) Ben A Adams. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-using System.Reflection;
+namespace Ben.Demystifier;
-namespace Ben.Demystifier
+public class EnhancedStackFrame : StackFrame
{
- public class EnhancedStackFrame : StackFrame
+ private readonly int _colNumber;
+ private readonly string? _fileName;
+ private readonly int _lineNumber;
+
+ internal EnhancedStackFrame(StackFrame stackFrameBase, ResolvedMethod methodInfo, string? fileName, int lineNumber,
+ int colNumber)
+ : base(fileName, lineNumber, colNumber)
{
- private readonly string? _fileName;
- private readonly int _lineNumber;
- private readonly int _colNumber;
-
- public StackFrame StackFrame { get; }
-
- public bool IsRecursive
- {
- get => MethodInfo.RecurseCount > 0;
- internal set => MethodInfo.RecurseCount++;
- }
-
- public ResolvedMethod MethodInfo { get; }
-
- internal EnhancedStackFrame(StackFrame stackFrame, ResolvedMethod methodInfo, string? fileName, int lineNumber, int colNumber)
- : base(fileName, lineNumber, colNumber)
- {
- StackFrame = stackFrame;
- MethodInfo = methodInfo;
-
- _fileName = fileName;
- _lineNumber = lineNumber;
- _colNumber = colNumber;
- }
-
- internal bool IsEquivalent(ResolvedMethod methodInfo, string? fileName, int lineNumber, int colNumber)
- {
- return _lineNumber == lineNumber &&
- _colNumber == colNumber &&
- _fileName == fileName &&
- MethodInfo.IsSequentialEquivalent(methodInfo);
- }
-
- ///
- /// Gets the column number in the file that contains the code that is executing.
- /// This information is typically extracted from the debugging symbols for the executable.
- ///
- /// The file column number, or 0 (zero) if the file column number cannot be determined.
- public override int GetFileColumnNumber() => _colNumber;
-
- ///
- /// Gets the line number in the file that contains the code that is executing.
- /// This information is typically extracted from the debugging symbols for the executable.
- ///
- /// The file line number, or 0 (zero) if the file line number cannot be determined.
- public override int GetFileLineNumber() => _lineNumber;
-
- ///
- /// Gets the file name that contains the code that is executing.
- /// This information is typically extracted from the debugging symbols for the executable.
- ///
- /// The file name, or null if the file name cannot be determined.
- public override string? GetFileName() => _fileName;
-
- ///
- /// Gets the offset from the start of the Microsoft intermediate language (MSIL)
- /// code for the method that is executing. This offset might be an approximation
- /// depending on whether or not the just-in-time (JIT) compiler is generating debugging
- /// code. The generation of this debugging information is controlled by the System.Diagnostics.DebuggableAttribute.
- ///
- /// The offset from the start of the MSIL code for the method that is executing.
- public override int GetILOffset() => StackFrame.GetILOffset();
-
- ///
- /// Gets the method in which the frame is executing.
- ///
- /// The method in which the frame is executing.
- public override MethodBase? GetMethod() => StackFrame.GetMethod();
-
- ///
- /// Gets the offset from the start of the native just-in-time (JIT)-compiled code
- /// for the method that is being executed. The generation of this debugging information
- /// is controlled by the System.Diagnostics.DebuggableAttribute class.
- ///
- /// The offset from the start of the JIT-compiled code for the method that is being executed.
- public override int GetNativeOffset() => StackFrame.GetNativeOffset();
-
- ///
- /// Builds a readable representation of the stack trace.
- ///
- /// A readable representation of the stack trace.
- public override string ToString() => MethodInfo.ToString();
+ StackFrameBase = stackFrameBase;
+ MethodInfo = methodInfo;
+ _fileName = fileName;
+ _lineNumber = lineNumber;
+ _colNumber = colNumber;
}
-}
+
+ private StackFrame StackFrameBase { get; }
+
+ public bool IsRecursive
+ {
+ get => MethodInfo.RecurseCount > 0;
+ internal set => MethodInfo.RecurseCount++;
+ }
+
+ public ResolvedMethod MethodInfo { get; }
+
+ internal bool IsEquivalent(ResolvedMethod methodInfo, string? fileName, int lineNumber, int colNumber) =>
+ _lineNumber == lineNumber &&
+ _colNumber == colNumber &&
+ _fileName == fileName &&
+ MethodInfo.IsSequentialEquivalent(methodInfo);
+
+ ///
+ /// Gets the column number in the file that contains the code that is executing.
+ /// This information is typically extracted from the debugging symbols for the executable.
+ ///
+ /// The file column number, or 0 (zero) if the file column number cannot be determined.
+ public override int GetFileColumnNumber() => _colNumber;
+
+ ///
+ /// Gets the line number in the file that contains the code that is executing.
+ /// This information is typically extracted from the debugging symbols for the executable.
+ ///
+ /// The file line number, or 0 (zero) if the file line number cannot be determined.
+ public override int GetFileLineNumber() => _lineNumber;
+
+ ///
+ /// Gets the file name that contains the code that is executing.
+ /// This information is typically extracted from the debugging symbols for the executable.
+ ///
+ /// The file name, or null if the file name cannot be determined.
+ public override string? GetFileName() => _fileName;
+
+ ///
+ /// Gets the offset from the start of the Microsoft intermediate language (MSIL)
+ /// code for the method that is executing. This offset might be an approximation
+ /// depending on whether or not the just-in-time (JIT) compiler is generating debugging
+ /// code. The generation of this debugging information is controlled by the System.Diagnostics.DebuggableAttribute.
+ ///
+ /// The offset from the start of the MSIL code for the method that is executing.
+ public override int GetILOffset() => StackFrameBase.GetILOffset();
+
+ /// Gets the method in which the frame is executing.
+ /// The method in which the frame is executing.
+ public override MethodBase? GetMethod() => StackFrameBase.GetMethod();
+
+ ///
+ /// Gets the offset from the start of the native just-in-time (JIT)-compiled code
+ /// for the method that is being executed. The generation of this debugging information
+ /// is controlled by the System.Diagnostics.DebuggableAttribute class.
+ ///
+ /// The offset from the start of the JIT-compiled code for the method that is being executed.
+ public override int GetNativeOffset() => StackFrameBase.GetNativeOffset();
+
+ /// Builds a readable representation of the stack trace.
+ /// A readable representation of the stack trace.
+ public override string ToString() => MethodInfo.ToString();
+}
\ No newline at end of file
diff --git a/src/Ben.Demystifier/EnhancedStackTrace.Frames.cs b/src/Ben.Demystifier/EnhancedStackTrace.Frames.cs
index b224152..54efcc4 100644
--- a/src/Ben.Demystifier/EnhancedStackTrace.Frames.cs
+++ b/src/Ben.Demystifier/EnhancedStackTrace.Frames.cs
@@ -3,28 +3,27 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-global using System.Collections;
-global using System.Collections.Generic;
-using Ben.Demystifier.Enumerable;
-using Ben.Demystifier.Internal;
using System.Linq;
-using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.ExceptionServices;
-using System.Text;
using System.Threading;
using System.Threading.Tasks;
+using Ben.Demystifier.Enumerable;
+using Ben.Demystifier.Internal;
namespace Ben.Demystifier
{
public partial class EnhancedStackTrace
{
- private static readonly Type? StackTraceHiddenAttributeType = Type.GetType("System.Diagnostics.StackTraceHiddenAttribute", false);
- private static readonly Type? AsyncIteratorStateMachineAttributeType = Type.GetType("System.Runtime.CompilerServices.AsyncIteratorStateMachineAttribute", false);
+ private static readonly Type? StackTraceHiddenAttributeType =
+ Type.GetType("System.Diagnostics.StackTraceHiddenAttribute", false);
+
+ private static readonly Type? AsyncIteratorStateMachineAttributeType =
+ Type.GetType("System.Runtime.CompilerServices.AsyncIteratorStateMachineAttribute", false);
static EnhancedStackTrace()
{
- if (AsyncIteratorStateMachineAttributeType != null) return;
+ if (AsyncIteratorStateMachineAttributeType is not null) return;
Assembly mba;
try
@@ -36,32 +35,15 @@ namespace Ben.Demystifier
return;
}
- AsyncIteratorStateMachineAttributeType = mba.GetType("System.Runtime.CompilerServices.AsyncIteratorStateMachineAttribute", false);
- }
-
- private static List GetFrames(Exception exception)
- {
- if (exception == null)
- {
- return new List();
- }
-
- var needFileInfo = true;
- var stackTrace = new StackTrace(exception, needFileInfo);
-
- return GetFrames(stackTrace);
+ AsyncIteratorStateMachineAttributeType =
+ mba.GetType("System.Runtime.CompilerServices.AsyncIteratorStateMachineAttribute", false);
}
public static List GetFrames(StackTrace stackTrace)
{
- var frames = new List();
+ var enhancedFrames = new List();
var stackFrames = stackTrace.GetFrames();
- if (stackFrames == null)
- {
- return frames;
- }
-
EnhancedStackFrame? lastFrame = null;
PortablePdbReader? portablePdbReader = null;
try
@@ -69,27 +51,22 @@ namespace Ben.Demystifier
for (var i = 0; i < stackFrames.Length; i++)
{
var frame = stackFrames[i];
- if (frame is null)
- {
- continue;
- }
var method = frame.GetMethod();
// Always show last stackFrame
- if (method != null && !ShowInStackTrace(method) && i < stackFrames.Length - 1)
- {
+ if (method is not null && !ShowInStackTrace(method) && i < stackFrames.Length - 1)
continue;
- }
var fileName = frame.GetFileName();
var row = frame.GetFileLineNumber();
var column = frame.GetFileColumnNumber();
var ilOffset = frame.GetILOffset();
- if (method != null && string.IsNullOrEmpty(fileName) && ilOffset >= 0)
+ if (method is not null && string.IsNullOrEmpty(fileName) && ilOffset >= 0)
{
// .NET Framework and older versions of mono don't support portable PDBs
// so we read it manually to get file name and line information
- (portablePdbReader ??= new PortablePdbReader()).PopulateStackFrame(frame, method, frame.GetILOffset(), out fileName, out row, out column);
+ (portablePdbReader ??= new PortablePdbReader()).PopulateStackFrame(frame, method,
+ frame.GetILOffset(), out fileName, out row, out column);
}
if (method is null)
@@ -106,7 +83,7 @@ namespace Ben.Demystifier
else
{
var stackFrame = new EnhancedStackFrame(frame, resolvedMethod, fileName, row, column);
- frames.Add(stackFrame);
+ enhancedFrames.Add(stackFrame);
lastFrame = stackFrame;
}
}
@@ -116,7 +93,7 @@ namespace Ben.Demystifier
portablePdbReader?.Dispose();
}
- return frames;
+ return enhancedFrames;
}
public static ResolvedMethod GetMethodDisplayString(MethodBase originMethod)
@@ -161,7 +138,8 @@ namespace Ben.Demystifier
methodDisplayInfo.Name = methodName;
if (method.Name.IndexOf("<") >= 0)
{
- if (TryResolveGeneratedName(ref method, out type, out methodName, out subMethodName, out var kind, out var ordinal))
+ if (TryResolveGeneratedName(ref method, out type, out methodName, out subMethodName, out var kind,
+ out var ordinal))
{
methodName = method.Name;
methodDisplayInfo.MethodBase = method;
@@ -175,7 +153,7 @@ namespace Ben.Demystifier
methodDisplayInfo.IsLambda = (kind == GeneratedNameKind.LambdaMethod);
- if (methodDisplayInfo.IsLambda && type != null)
+ if (methodDisplayInfo.IsLambda && type is not null)
{
if (methodName == ".cctor")
{
@@ -185,7 +163,8 @@ namespace Ben.Demystifier
}
else
{
- var fields = type.GetFields(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
+ var fields =
+ type.GetFields(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
foreach (var field in fields)
{
var value = field.GetValue(field);
@@ -212,33 +191,29 @@ namespace Ben.Demystifier
}
// ResolveStateMachineMethod may have set declaringType to null
- if (type != null)
+ if (type is not null)
{
methodDisplayInfo.DeclaringType = type;
}
if (method is MethodInfo mi)
{
- var returnParameter = mi.ReturnParameter;
- if (returnParameter != null)
- {
+ if (mi.ReturnParameter is not null)
methodDisplayInfo.ReturnParameter = GetParameter(mi.ReturnParameter);
- }
- else if (mi.ReturnType != null)
- {
+ else if (mi.ReturnType is not null)
methodDisplayInfo.ReturnParameter = new ResolvedParameter(mi.ReturnType)
{
Prefix = "",
- Name = "",
+ Name = ""
};
- }
}
if (method.IsGenericMethod)
{
var genericArguments = method.GetGenericArguments();
var genericArgumentsString = string.Join(", ", genericArguments
- .Select(arg => TypeNameHelper.GetTypeDisplayName(arg, fullName: false, includeGenericParameterNames: true)));
+ .Select(arg =>
+ TypeNameHelper.GetTypeDisplayName(arg, fullName: false, includeGenericParameterNames: true)));
methodDisplayInfo.GenericArguments += "<" + genericArgumentsString + ">";
methodDisplayInfo.ResolvedGenericArguments = genericArguments;
}
@@ -260,7 +235,7 @@ namespace Ben.Demystifier
{
methodDisplayInfo.SubMethodBase = null;
}
- else if (methodDisplayInfo.SubMethodBase != null)
+ else if (methodDisplayInfo.SubMethodBase is not null)
{
parameters = methodDisplayInfo.SubMethodBase.GetParameters();
if (parameters.Length > 0)
@@ -295,7 +270,8 @@ namespace Ben.Demystifier
return false;
}
- private static bool TryResolveGeneratedName(ref MethodBase method, out Type? type, out string methodName, out string? subMethodName, out GeneratedNameKind kind, out int? ordinal)
+ private static bool TryResolveGeneratedName(ref MethodBase method, out Type? type, out string methodName,
+ out string? subMethodName, out GeneratedNameKind kind, out int? ordinal)
{
kind = GeneratedNameKind.None;
type = method.DeclaringType;
@@ -315,28 +291,29 @@ namespace Ben.Demystifier
switch (kind)
{
case GeneratedNameKind.LocalFunction:
- {
- var localNameStart = generatedName.IndexOf((char)kind, closeBracketOffset + 1);
- if (localNameStart < 0) break;
- localNameStart += 3;
+ {
+ var localNameStart = generatedName.IndexOf((char)kind, closeBracketOffset + 1);
+ if (localNameStart < 0) break;
+ localNameStart += 3;
- if (localNameStart < generatedName.Length)
+ if (localNameStart < generatedName.Length)
+ {
+ var localNameEnd = generatedName.IndexOf("|", localNameStart);
+ if (localNameEnd > 0)
{
- var localNameEnd = generatedName.IndexOf("|", localNameStart);
- if (localNameEnd > 0)
- {
- subMethodName = generatedName.Substring(localNameStart, localNameEnd - localNameStart);
- }
+ subMethodName = generatedName.Substring(localNameStart, localNameEnd - localNameStart);
}
- break;
}
+
+ break;
+ }
case GeneratedNameKind.LambdaMethod:
subMethodName = "";
break;
}
var dt = method.DeclaringType;
- if (dt == null)
+ if (dt is null)
{
return false;
}
@@ -345,30 +322,42 @@ namespace Ben.Demystifier
var matchName = methodName;
- var candidateMethods = dt.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance | BindingFlags.DeclaredOnly).Where(m => m.Name == matchName);
- if (TryResolveSourceMethod(candidateMethods, kind, matchHint, ref method, ref type, out ordinal)) return true;
+ var candidateMethods =
+ dt.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static |
+ BindingFlags.Instance | BindingFlags.DeclaredOnly).Where(m => m.Name == matchName);
+ if (TryResolveSourceMethod(candidateMethods, kind, matchHint, ref method, ref type, out ordinal))
+ return true;
- var candidateConstructors = dt.GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance | BindingFlags.DeclaredOnly).Where(m => m.Name == matchName);
- if (TryResolveSourceMethod(candidateConstructors, kind, matchHint, ref method, ref type, out ordinal)) return true;
+ var candidateConstructors =
+ dt.GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static |
+ BindingFlags.Instance | BindingFlags.DeclaredOnly).Where(m => m.Name == matchName);
+ if (TryResolveSourceMethod(candidateConstructors, kind, matchHint, ref method, ref type, out ordinal))
+ return true;
- const int MaxResolveDepth = 10;
- for (var i = 0; i < MaxResolveDepth; i++)
+ for (var i = 0; i < 10; i++)
{
dt = dt.DeclaringType;
- if (dt == null)
- {
+ if (dt is null)
return false;
- }
- candidateMethods = dt.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance | BindingFlags.DeclaredOnly).Where(m => m.Name == matchName);
- if (TryResolveSourceMethod(candidateMethods, kind, matchHint, ref method, ref type, out ordinal)) return true;
+ candidateMethods =
+ dt.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static |
+ BindingFlags.Instance | BindingFlags.DeclaredOnly).Where(m => m.Name == matchName);
+ if (TryResolveSourceMethod(candidateMethods, kind, matchHint, ref method, ref type, out ordinal))
+ return true;
- candidateConstructors = dt.GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance | BindingFlags.DeclaredOnly).Where(m => m.Name == matchName);
- if (TryResolveSourceMethod(candidateConstructors, kind, matchHint, ref method, ref type, out ordinal)) return true;
+ candidateConstructors =
+ dt.GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static |
+ BindingFlags.Instance | BindingFlags.DeclaredOnly)
+ .Where(m => m.Name == matchName);
+ if (TryResolveSourceMethod(candidateConstructors, kind, matchHint, ref method, ref type, out ordinal))
+ return true;
if (methodName == ".cctor")
{
- candidateConstructors = dt.GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.DeclaredOnly).Where(m => m.Name == matchName);
+ candidateConstructors =
+ dt.GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static |
+ BindingFlags.DeclaredOnly).Where(m => m.Name == matchName);
foreach (var cctor in candidateConstructors)
{
method = cctor;
@@ -381,7 +370,8 @@ namespace Ben.Demystifier
return false;
}
- private static bool TryResolveSourceMethod(IEnumerable candidateMethods, GeneratedNameKind kind, string? matchHint, ref MethodBase method, ref Type? type, out int? ordinal)
+ private static bool TryResolveSourceMethod(IEnumerable candidateMethods, GeneratedNameKind kind,
+ string? matchHint, ref MethodBase method, ref Type? type, out int? ordinal)
{
ordinal = null;
foreach (var candidateMethod in candidateMethods)
@@ -390,6 +380,7 @@ namespace Ben.Demystifier
{
continue;
}
+
if (kind == GeneratedNameKind.LambdaMethod)
{
foreach (var v in EnumerableIList.Create(methodBody.LocalVariables))
@@ -397,8 +388,8 @@ namespace Ben.Demystifier
if (v.LocalType == type)
{
GetOrdinal(method, ref ordinal);
-
}
+
method = candidateMethod;
type = method.DeclaringType;
return true;
@@ -412,12 +403,13 @@ namespace Ben.Demystifier
{
continue;
}
+
var reader = new ILReader(rawIl);
while (reader.Read(candidateMethod))
{
if (reader.Operand is MethodBase mb)
{
- if (method == mb || matchHint != null && method.Name.Contains(matchHint))
+ if (method == mb || matchHint is not null && method.Name.Contains(matchHint))
{
if (kind == GeneratedNameKind.LambdaMethod)
{
@@ -460,10 +452,12 @@ namespace Ben.Demystifier
ordinal = foundOrdinal;
- var methods = method.DeclaringType?.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance | BindingFlags.DeclaredOnly);
+ var methods = method.DeclaringType?.GetMethods(BindingFlags.Public | BindingFlags.NonPublic |
+ BindingFlags.Static | BindingFlags.Instance |
+ BindingFlags.DeclaredOnly);
var count = 0;
- if (methods != null)
+ if (methods is not null)
{
var startName = method.Name.Substring(0, lamdaStart);
foreach (var m in methods)
@@ -501,6 +495,7 @@ namespace Ben.Demystifier
return methodName.Substring(start, end - start);
}
+
return null;
}
@@ -517,13 +512,8 @@ namespace Ben.Demystifier
{
openBracketOffset = -1;
if (name.StartsWith("CS$<", StringComparison.Ordinal))
- {
openBracketOffset = 3;
- }
- else if (name.StartsWith("<", StringComparison.Ordinal))
- {
- openBracketOffset = 0;
- }
+ else if (name.StartsWith("<", StringComparison.Ordinal)) openBracketOffset = 0;
if (openBracketOffset >= 0)
{
@@ -549,50 +539,32 @@ namespace Ben.Demystifier
private static int IndexOfBalancedParenthesis(string str, int openingOffset, char closing)
{
var opening = str[openingOffset];
-
var depth = 1;
for (var i = openingOffset + 1; i < str.Length; i++)
{
var c = str[i];
if (c == opening)
- {
depth++;
- }
else if (c == closing)
{
depth--;
if (depth == 0)
- {
return i;
- }
}
}
-
return -1;
}
private static string GetPrefix(ParameterInfo parameter)
{
if (Attribute.IsDefined(parameter, typeof(ParamArrayAttribute), false))
- {
return "params";
- }
-
if (parameter.IsOut)
- {
return "out";
- }
-
if (parameter.IsIn)
- {
return "in";
- }
-
if (parameter.ParameterType.IsByRef)
- {
return "ref";
- }
-
return string.Empty;
}
@@ -605,20 +577,16 @@ namespace Ben.Demystifier
{
var customAttribs = parameter.GetCustomAttributes(inherit: false);
- var tupleNameAttribute = customAttribs.OfType().FirstOrDefault(a => a.IsTupleElementNameAttribute());
+ var tupleNameAttribute = customAttribs.OfType()
+ .FirstOrDefault(a => a.IsTupleElementNameAttribute());
var tupleNames = tupleNameAttribute?.GetTransformerNames();
if (tupleNames?.Count > 0)
- {
return GetValueTupleParameter(tupleNames, prefix, parameter.Name, parameterType);
- }
}
- if (parameterType.IsByRef && parameterType.GetElementType() is {} elementType)
- {
- parameterType = elementType;
- }
+ if (parameterType.IsByRef && parameterType.GetElementType() is { } elementType) parameterType = elementType;
return new ResolvedParameter(parameterType)
{
@@ -628,48 +596,16 @@ namespace Ben.Demystifier
};
}
- private static ResolvedParameter GetValueTupleParameter(IList tupleNames, string prefix, string? name, Type parameterType)
+ private static ResolvedParameter GetValueTupleParameter(IList tupleNames, string prefix, string? name,
+ Type parameterType)
{
return new ValueTupleResolvedParameter(parameterType, tupleNames)
{
Prefix = prefix,
- Name = name,
+ Name = name
};
}
- private static string GetValueTupleParameterName(IList tupleNames, Type parameterType)
- {
- var sb = new StringBuilder();
- sb.Append("(");
- var args = parameterType.GetGenericArguments();
- for (var i = 0; i < args.Length; i++)
- {
- if (i > 0)
- {
- sb.Append(", ");
- }
-
- sb.Append(TypeNameHelper.GetTypeDisplayName(args[i], fullName: false, includeGenericParameterNames: true));
-
- if (i >= tupleNames.Count)
- {
- continue;
- }
-
- var argName = tupleNames[i];
- if (argName == null)
- {
- continue;
- }
-
- sb.Append(" ");
- sb.Append(argName);
- }
-
- sb.Append(")");
- return sb.ToString();
- }
-
private static bool ShowInStackTrace(MethodBase method)
{
// Since .NET 5:
@@ -684,7 +620,7 @@ namespace Ben.Demystifier
}
// Since .NET Core 2:
- if (StackTraceHiddenAttributeType != null)
+ if (StackTraceHiddenAttributeType is not null)
{
// Don't show any methods marked with the StackTraceHiddenAttribute
// https://github.com/dotnet/coreclr/pull/14652
@@ -696,13 +632,13 @@ namespace Ben.Demystifier
var type = method.DeclaringType;
- if (type == null)
+ if (type is null)
{
return true;
}
// Since .NET Core 2:
- if (StackTraceHiddenAttributeType != null)
+ if (StackTraceHiddenAttributeType is not null)
{
// Don't show any methods marked with the StackTraceHiddenAttribute
// https://github.com/dotnet/coreclr/pull/14652
@@ -716,18 +652,24 @@ namespace Ben.Demystifier
{
return false;
}
+
if (type == typeof(ValueTask<>) && method.Name == "get_Result")
{
return false;
}
- if (method.Name.StartsWith("System.Threading.Tasks.Sources.IValueTaskSource") && method.Name.EndsWith(".GetResult"))
+
+ if (method.Name.StartsWith("System.Threading.Tasks.Sources.IValueTaskSource") &&
+ method.Name.EndsWith(".GetResult"))
{
return false;
}
- if (method.Name == "GetResult" && method.DeclaringType?.FullName == "System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore`1")
+
+ if (method.Name == "GetResult" && method.DeclaringType?.FullName ==
+ "System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore`1")
{
return false;
}
+
if (type == typeof(Task) || type.DeclaringType == typeof(Task))
{
if (method.Name.Contains(".cctor"))
@@ -747,12 +689,11 @@ namespace Ben.Demystifier
return false;
}
}
+
if (type == typeof(ExecutionContext))
{
if (method.Name.Contains(".cctor"))
- {
return false;
- }
switch (method.Name)
{
@@ -821,9 +762,7 @@ namespace Ben.Demystifier
private static bool IsStackTraceHidden(MemberInfo memberInfo)
{
if (StackTraceHiddenAttributeType is not null && !memberInfo.Module.Assembly.ReflectionOnly)
- {
return memberInfo.GetCustomAttributes(StackTraceHiddenAttributeType, false).Length != 0;
- }
EnumerableIList attributes;
try
@@ -835,8 +774,9 @@ namespace Ben.Demystifier
return false;
}
- foreach (var attribute in attributes)
+ for (var i = 0; i < attributes.Count; i++)
{
+ var attribute = attributes[i];
// reflection-only attribute, match on name
if (attribute.AttributeType.FullName == StackTraceHiddenAttributeType?.FullName)
{
@@ -855,6 +795,7 @@ namespace Ben.Demystifier
declaringType = null!;
return false;
}
+
declaringType = method.DeclaringType;
var parentType = declaringType.DeclaringType;
@@ -863,11 +804,9 @@ namespace Ben.Demystifier
return false;
}
- static MethodInfo[] GetDeclaredMethods(Type type) =>
- type.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance | BindingFlags.DeclaredOnly);
-
- var methods = GetDeclaredMethods(parentType);
- if (methods == null)
+ var methods = parentType.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static |
+ BindingFlags.Instance | BindingFlags.DeclaredOnly);
+ if (methods is null)
{
return false;
}
@@ -888,8 +827,8 @@ namespace Ben.Demystifier
{
foundAttribute = true;
foundIteratorAttribute |= asma is IteratorStateMachineAttribute
- || AsyncIteratorStateMachineAttributeType != null
- && AsyncIteratorStateMachineAttributeType.IsInstanceOfType(asma);
+ || AsyncIteratorStateMachineAttributeType is not null
+ && AsyncIteratorStateMachineAttributeType.IsInstanceOfType(asma);
}
}
@@ -903,6 +842,7 @@ namespace Ben.Demystifier
return foundIteratorAttribute;
}
}
+
return false;
}
@@ -917,7 +857,9 @@ namespace Ben.Demystifier
LambdaMethod = 'b',
LambdaDisplayClass = 'c',
StateMachineType = 'd',
- LocalFunction = 'g', // note collision with Deprecated_InitializerLocal, however this one is only used for method names
+
+ LocalFunction =
+ 'g', // note collision with Deprecated_InitializerLocal, however this one is only used for method names
// Used by EnC:
AwaiterField = 'u',
@@ -942,4 +884,4 @@ namespace Ben.Demystifier
DynamicCallSiteField = 'p'
}
}
-}
+}
\ No newline at end of file
diff --git a/src/Ben.Demystifier/EnhancedStackTrace.cs b/src/Ben.Demystifier/EnhancedStackTrace.cs
index 933e60d..c4e13f9 100644
--- a/src/Ben.Demystifier/EnhancedStackTrace.cs
+++ b/src/Ben.Demystifier/EnhancedStackTrace.cs
@@ -1,141 +1,89 @@
// Copyright (c) Ben A Adams. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-using System.Collections;
-using System.Collections.Generic;
-using Ben.Demystifier.Enumerable;
-using System.IO;
-using System.Text;
+namespace Ben.Demystifier;
-namespace Ben.Demystifier
+public partial class EnhancedStackTrace : StackTrace, IEnumerable
{
- public partial class EnhancedStackTrace : StackTrace, IEnumerable
+ private readonly List _frames;
+
+ ///
+ /// Initializes a new instance of the System.Diagnostics.StackTrace class using the
+ /// provided exception object
+ ///
+ public EnhancedStackTrace(Exception e)
{
- public static EnhancedStackTrace Current() => new EnhancedStackTrace(new StackTrace(1 /* skip this one frame */, true));
+ _frames = GetFrames(new StackTrace(e, true));
+ }
- private readonly List _frames;
+ public EnhancedStackTrace(StackTrace stackTrace)
+ {
+ _frames = GetFrames(stackTrace);
+ }
- // Summary:
- // Initializes a new instance of the System.Diagnostics.StackTrace class using the
- // provided exception object.
- //
- // Parameters:
- // e:
- // The exception object from which to construct the stack trace.
- //
- // Exceptions:
- // T:System.ArgumentNullException:
- // The parameter e is null.
- public EnhancedStackTrace(Exception e)
+ /// The number of frames in the stack trace.
+ public override int FrameCount => _frames.Count;
+
+ IEnumerator IEnumerable.GetEnumerator() => _frames.GetEnumerator();
+
+ IEnumerator IEnumerable.GetEnumerator() => _frames.GetEnumerator();
+
+ public static EnhancedStackTrace Current()
+ => new EnhancedStackTrace(new StackTrace(1 /* skip this one frame */, true));
+
+ /// The index of the stack frame requested.
+ /// The specified stack frame.
+ public override StackFrame GetFrame(int index) => _frames[index];
+
+ /// a copy of all stack frames in the current stack trace.
+ public override StackFrame[] GetFrames() => _frames.ToArray();
+
+ ///
+ /// Builds a readable representation of the stack trace.
+ ///
+ public override string ToString()
+ {
+ if (_frames.Count == 0) return "";
+
+ var sb = new StringBuilder();
+ AppendTo(sb);
+ return sb.ToString();
+ }
+
+ public void AppendTo(StringBuilder sb)
+ {
+ var count = _frames.Count;
+ for (var i = 0; i < count; i++)
{
- if (e == null)
+ if (i > 0) sb.Append(Environment.NewLine);
+ var frame = _frames[i];
+ sb.Append(" at ");
+ frame.MethodInfo.AppendTo(sb);
+
+ var fileName = frame.GetFileName();
+ if (!string.IsNullOrEmpty(fileName))
{
- throw new ArgumentNullException(nameof(e));
+ sb.Append(" in ");
+ sb.Append(TryGetFullPath(fileName));
}
- _frames = GetFrames(e);
- }
-
-
- public EnhancedStackTrace(StackTrace stackTrace)
- {
- if (stackTrace == null)
+ var lineNo = frame.GetFileLineNumber();
+ if (lineNo != 0)
{
- throw new ArgumentNullException(nameof(stackTrace));
+ sb.Append(":line ");
+ sb.Append(lineNo);
}
-
- _frames = GetFrames(stackTrace);
- }
-
- ///
- /// Gets the number of frames in the stack trace.
- ///
- /// The number of frames in the stack trace.
- public override int FrameCount => _frames.Count;
-
- ///
- /// Gets the specified stack frame.
- ///
- /// The index of the stack frame requested.
- /// The specified stack frame.
- public override StackFrame GetFrame(int index) => _frames[index];
-
- ///
- /// Returns a copy of all stack frames in the current stack trace.
- ///
- ///
- /// An array of type System.Diagnostics.StackFrame representing the function calls
- /// in the stack trace.
- ///
- public override StackFrame[] GetFrames() => _frames.ToArray();
-
- ///
- /// Builds a readable representation of the stack trace.
- ///
- /// A readable representation of the stack trace.
- public override string ToString()
- {
- if (_frames == null || _frames.Count == 0) return "";
-
- var sb = new StringBuilder();
-
- Append(sb);
-
- return sb.ToString();
- }
-
-
- internal void Append(StringBuilder sb)
- {
- var frames = _frames;
- var count = frames.Count;
-
- for (var i = 0; i < count; i++)
- {
- if (i > 0)
- {
- sb.Append(Environment.NewLine);
- }
-
- var frame = frames[i];
-
- sb.Append(" at ");
- frame.MethodInfo.Append(sb);
-
- if (frame.GetFileName() is {} fileName
- // IsNullOrEmpty alone wasn't enough to disable the null warning
- && !string.IsNullOrEmpty(fileName))
- {
- sb.Append(" in ");
- sb.Append(TryGetFullPath(fileName));
-
- }
-
- var lineNo = frame.GetFileLineNumber();
- if (lineNo != 0)
- {
- sb.Append(":line ");
- sb.Append(lineNo);
- }
- }
- }
-
- EnumerableIList GetEnumerator() => EnumerableIList.Create(_frames);
- IEnumerator IEnumerable.GetEnumerator() => _frames.GetEnumerator();
- IEnumerator IEnumerable.GetEnumerator() => _frames.GetEnumerator();
-
- ///
- /// Tries to convert a given to a full path.
- /// Returns original value if the conversion isn't possible or a given path is relative.
- ///
- public static string TryGetFullPath(string filePath)
- {
- if (Uri.TryCreate(filePath, UriKind.Absolute, out var uri) && uri.IsFile)
- {
- return Uri.UnescapeDataString(uri.AbsolutePath);
- }
-
- return filePath;
}
}
-}
+
+ ///
+ /// Tries to convert a given to a full path.
+ /// Returns original value if the conversion isn't possible or a given path is relative.
+ ///
+ public static string TryGetFullPath(string filePath)
+ {
+ if (Uri.TryCreate(filePath, UriKind.Absolute, out var uri) && uri.IsFile)
+ return Uri.UnescapeDataString(uri.AbsolutePath);
+ return filePath;
+ }
+}
\ No newline at end of file
diff --git a/src/Ben.Demystifier/Enumerable/EnumerableIList.cs b/src/Ben.Demystifier/Enumerable/EnumerableIList.cs
index 478219a..9eb9502 100644
--- a/src/Ben.Demystifier/Enumerable/EnumerableIList.cs
+++ b/src/Ben.Demystifier/Enumerable/EnumerableIList.cs
@@ -1,65 +1,77 @@
// Copyright (c) Ben A Adams. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-namespace Ben.Demystifier.Enumerable
+namespace Ben.Demystifier.Enumerable;
+
+public static class EnumerableIList
{
- public static class EnumerableIList
+ public static EnumerableIList Create(IList list)
{
- public static EnumerableIList Create(IList list) => new EnumerableIList(list);
- }
-
- public struct EnumerableIList : IEnumerableIList, IList
- {
- private readonly IList _list;
-
- public EnumerableIList(IList list) => _list = list;
-
- public EnumeratorIList GetEnumerator() => new EnumeratorIList(_list);
-
- public static implicit operator EnumerableIList(List list) => new EnumerableIList(list);
-
- public static implicit operator EnumerableIList(T[] array) => new EnumerableIList(array);
-
- public static EnumerableIList Empty = default;
-
-
- // IList pass through
-
- ///
- public T this[int index] { get => _list[index]; set => _list[index] = value; }
-
- ///
- public int Count => _list.Count;
-
- ///
- public bool IsReadOnly => _list.IsReadOnly;
-
- ///
- public void Add(T item) => _list.Add(item);
-
- ///
- public void Clear() => _list.Clear();
-
- ///
- public bool Contains(T item) => _list.Contains(item);
-
- ///
- public void CopyTo(T[] array, int arrayIndex) => _list.CopyTo(array, arrayIndex);
-
- ///
- public int IndexOf(T item) => _list.IndexOf(item);
-
- ///
- public void Insert(int index, T item) => _list.Insert(index, item);
-
- ///
- public bool Remove(T item) => _list.Remove(item);
-
- ///
- public void RemoveAt(int index) => _list.RemoveAt(index);
-
- IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
-
- IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
+ return new(list);
}
}
+
+public struct EnumerableIList : IEnumerableIList, IList
+{
+ private readonly IList _list;
+
+ public EnumerableIList(IList list) => _list = list;
+
+ public EnumeratorIList GetEnumerator() => new(_list);
+
+ public static implicit operator EnumerableIList(List list) => new(list);
+
+ public static implicit operator EnumerableIList(T[] array) => new(array);
+
+ public static EnumerableIList Empty = default;
+
+
+ // IList pass through
+
+ ///
+ public T this[int index]
+ {
+ get => _list[index];
+ set => _list[index] = value;
+ }
+
+ ///
+ public int Count => _list.Count;
+
+ ///
+ public bool IsReadOnly => _list.IsReadOnly;
+
+ ///
+ public void Add(T item) => _list.Add(item);
+
+ ///
+ public void Clear() => _list.Clear();
+
+ ///
+ public bool Contains(T item) => _list.Contains(item);
+
+ ///
+ public void CopyTo(T[] array, int arrayIndex) => _list.CopyTo(array, arrayIndex);
+
+ ///
+ public int IndexOf(T item) => _list.IndexOf(item);
+
+ ///
+ public void Insert(int index, T item) => _list.Insert(index, item);
+
+ ///
+ public bool Remove(T item) => _list.Remove(item);
+
+ ///
+ public void RemoveAt(int index) => _list.RemoveAt(index);
+
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return GetEnumerator();
+ }
+
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return GetEnumerator();
+ }
+}
\ No newline at end of file
diff --git a/src/Ben.Demystifier/Enumerable/EnumeratorIList.cs b/src/Ben.Demystifier/Enumerable/EnumeratorIList.cs
index 3629166..31c0ace 100644
--- a/src/Ben.Demystifier/Enumerable/EnumeratorIList.cs
+++ b/src/Ben.Demystifier/Enumerable/EnumeratorIList.cs
@@ -1,30 +1,35 @@
// Copyright (c) Ben A Adams. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-namespace Ben.Demystifier.Enumerable
+namespace Ben.Demystifier.Enumerable;
+
+public struct EnumeratorIList : IEnumerator
{
- public struct EnumeratorIList : IEnumerator
+ private readonly IList _list;
+ private int _index;
+
+ public EnumeratorIList(IList list)
{
- private readonly IList _list;
- private int _index;
-
- public EnumeratorIList(IList list)
- {
- _index = -1;
- _list = list;
- }
-
- public T Current => _list[_index];
-
- public bool MoveNext()
- {
- _index++;
-
- return _index < (_list?.Count ?? 0);
- }
-
- public void Dispose() { }
- object? IEnumerator.Current => Current;
- public void Reset() => _index = -1;
+ _index = -1;
+ _list = list;
}
-}
+
+ public T Current => _list[_index];
+
+ public bool MoveNext()
+ {
+ _index++;
+
+ return _index < (_list?.Count ?? 0);
+ }
+
+ public void Dispose()
+ { }
+
+ object? IEnumerator.Current => Current;
+
+ public void Reset()
+ {
+ _index = -1;
+ }
+}
\ No newline at end of file
diff --git a/src/Ben.Demystifier/Enumerable/IEnumerableIList.cs b/src/Ben.Demystifier/Enumerable/IEnumerableIList.cs
index 13e848a..fcee75a 100644
--- a/src/Ben.Demystifier/Enumerable/IEnumerableIList.cs
+++ b/src/Ben.Demystifier/Enumerable/IEnumerableIList.cs
@@ -1,10 +1,9 @@
// Copyright (c) Ben A Adams. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-namespace Ben.Demystifier.Enumerable
+namespace Ben.Demystifier.Enumerable;
+
+internal interface IEnumerableIList : IEnumerable
{
- interface IEnumerableIList : IEnumerable
- {
- new EnumeratorIList GetEnumerator();
- }
-}
+ new EnumeratorIList GetEnumerator();
+}
\ No newline at end of file
diff --git a/src/Ben.Demystifier/ExceptionExtensions.cs b/src/Ben.Demystifier/ExceptionExtensions.cs
index ce88c02..36b2c44 100644
--- a/src/Ben.Demystifier/ExceptionExtensions.cs
+++ b/src/Ben.Demystifier/ExceptionExtensions.cs
@@ -1,66 +1,66 @@
// Copyright (c) Ben A Adams. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-global using System.Diagnostics;
global using System;
+global using System.Text;
+global using System.Collections;
+global using System.Collections.Generic;
+global using System.Diagnostics;
+global using System.Reflection;
+global using System.Linq;
using System.Diagnostics.Contracts;
-using System.Collections.Generic;
using Ben.Demystifier.Enumerable;
-using System.Reflection;
-using System.Text;
-namespace Ben.Demystifier
+namespace Ben.Demystifier;
+
+public static class ExceptionExtensions
{
- public static class ExceptionExtensions
+ private static readonly FieldInfo? StackTraceString =
+ typeof(Exception).GetField("_stackTraceString", BindingFlags.Instance | BindingFlags.NonPublic);
+
+ private static void SetStackTracesString(this Exception exception, string value)
{
- private static readonly FieldInfo? stackTraceString = typeof(Exception).GetField("_stackTraceString", BindingFlags.Instance | BindingFlags.NonPublic);
+ StackTraceString?.SetValue(exception, value);
+ }
- private static void SetStackTracesString(this Exception exception, string value)
- => stackTraceString?.SetValue(exception, value);
-
- ///
- /// Demystifies the given and tracks the original stack traces for the whole exception tree.
- ///
- public static T Demystify(this T exception) where T : Exception
+ ///
+ /// Demystifies the given and tracks the original stack traces for the whole exception
+ /// tree.
+ ///
+ public static T Demystify(this T exception) where T : Exception
+ {
+ try
{
- try
- {
- var stackTrace = new EnhancedStackTrace(exception);
+ var stackTrace = new EnhancedStackTrace(exception);
- if (stackTrace.FrameCount > 0)
- {
- exception.SetStackTracesString(stackTrace.ToString());
- }
+ if (stackTrace.FrameCount > 0) exception.SetStackTracesString(stackTrace.ToString());
- if (exception is AggregateException aggEx)
- {
- foreach (var ex in EnumerableIList.Create(aggEx.InnerExceptions))
- {
- ex.Demystify();
- }
- }
+ if (exception is AggregateException aggEx)
+ foreach (var ex in EnumerableIList.Create(aggEx.InnerExceptions))
+ ex.Demystify();
- exception.InnerException?.Demystify();
- }
- catch
- {
- // Processing exceptions shouldn't throw exceptions; if it fails
- }
-
- return exception;
+ exception.InnerException?.Demystify();
+ }
+ catch
+ {
+ // Processing exceptions shouldn't throw exceptions; if it fails
}
- ///
- /// Gets demystified string representation of the .
- ///
- ///
- /// method mutates the exception instance that can cause
- /// issues if a system relies on the stack trace be in the specific form.
- /// Unlike this method is pure. It calls first,
- /// computes a demystified string representation and then restores the original state of the exception back.
- ///
- [Pure]
- public static string ToStringDemystified(this Exception exception)
- => new StringBuilder().AppendDemystified(exception).ToString();
+ return exception;
}
-}
+
+ ///
+ /// Gets demystified string representation of the .
+ ///
+ ///
+ /// method mutates the exception instance that can cause
+ /// issues if a system relies on the stack trace be in the specific form.
+ /// Unlike this method is pure. It calls first,
+ /// computes a demystified string representation and then restores the original state of the exception back.
+ ///
+ [Pure]
+ public static string ToStringDemystified(this Exception exception)
+ {
+ return new StringBuilder().AppendDemystified(exception).ToString();
+ }
+}
\ No newline at end of file
diff --git a/src/Ben.Demystifier/Internal/ILReader.cs b/src/Ben.Demystifier/Internal/ILReader.cs
index 29bc436..eb236af 100644
--- a/src/Ben.Demystifier/Internal/ILReader.cs
+++ b/src/Ben.Demystifier/Internal/ILReader.cs
@@ -1,145 +1,145 @@
-using System.Reflection;
using System.Reflection.Emit;
-namespace Ben.Demystifier.Internal
+namespace Ben.Demystifier.Internal;
+
+internal class ILReader
{
- internal class ILReader
+ private static readonly OpCode[] singleByteOpCode;
+ private static readonly OpCode[] doubleByteOpCode;
+
+ private readonly byte[] _cil;
+ private int ptr;
+
+ static ILReader()
{
- private static OpCode[] singleByteOpCode;
- private static OpCode[] doubleByteOpCode;
+ singleByteOpCode = new OpCode[225];
+ doubleByteOpCode = new OpCode[31];
- private readonly byte[] _cil;
- private int ptr;
+ var fields = GetOpCodeFields();
-
- public ILReader(byte[] cil) => _cil = cil;
-
- public OpCode OpCode { get; private set; }
- public int MetadataToken { get; private set; }
- public MemberInfo? Operand { get; private set; }
-
- public bool Read(MethodBase methodInfo)
+ for (var i = 0; i < fields.Length; i++)
{
- if (ptr < _cil.Length)
- {
- OpCode = ReadOpCode();
- Operand = ReadOperand(OpCode, methodInfo);
- return true;
- }
- return false;
- }
+ var code = (OpCode)fields[i].GetValue(null)!;
+ if (code.OpCodeType == OpCodeType.Nternal)
+ continue;
- OpCode ReadOpCode()
- {
- var instruction = ReadByte();
- if (instruction < 254)
- return singleByteOpCode[instruction];
+ if (code.Size == 1)
+ singleByteOpCode[code.Value] = code;
else
- return doubleByteOpCode[ReadByte()];
+ doubleByteOpCode[code.Value & 0xff] = code;
}
-
- MemberInfo? ReadOperand(OpCode code, MethodBase methodInfo)
- {
- MetadataToken = 0;
- int inlineLength;
- switch (code.OperandType)
- {
- case OperandType.InlineMethod:
- MetadataToken = ReadInt();
- Type[]? methodArgs = null;
- if (methodInfo.GetType() != typeof(ConstructorInfo) && !methodInfo.GetType().IsSubclassOf(typeof(ConstructorInfo)))
- {
- methodArgs = methodInfo.GetGenericArguments();
- }
- Type[]? typeArgs = null;
- if (methodInfo.DeclaringType != null)
- {
- typeArgs = methodInfo.DeclaringType.GetGenericArguments();
- }
- try
- {
- return methodInfo.Module.ResolveMember(MetadataToken, typeArgs, methodArgs);
- }
- catch
- {
- // Can return System.ArgumentException : Token xxx is not a valid MemberInfo token in the scope of module xxx.dll
- return null;
- }
-
- case OperandType.InlineNone:
- inlineLength = 0;
- break;
-
- case OperandType.ShortInlineBrTarget:
- case OperandType.ShortInlineVar:
- case OperandType.ShortInlineI:
- inlineLength = 1;
- break;
-
- case OperandType.InlineVar:
- inlineLength = 2;
- break;
-
- case OperandType.InlineBrTarget:
- case OperandType.InlineField:
- case OperandType.InlineI:
- case OperandType.InlineString:
- case OperandType.InlineSig:
- case OperandType.InlineSwitch:
- case OperandType.InlineTok:
- case OperandType.InlineType:
- case OperandType.ShortInlineR:
- inlineLength = 4;
- break;
-
- case OperandType.InlineI8:
- case OperandType.InlineR:
- inlineLength = 8;
- break;
-
- default:
- return null;
- }
-
- for (var i = 0; i < inlineLength; i++)
- {
- ReadByte();
- }
-
- return null;
- }
-
- byte ReadByte() => _cil[ptr++];
-
- int ReadInt()
- {
- var b1 = ReadByte();
- var b2 = ReadByte();
- var b3 = ReadByte();
- var b4 = ReadByte();
- return b1 | b2 << 8 | b3 << 16 | b4 << 24;
- }
-
- static ILReader()
- {
- singleByteOpCode = new OpCode[225];
- doubleByteOpCode = new OpCode[31];
-
- var fields = GetOpCodeFields();
-
- for (var i = 0; i < fields.Length; i++)
- {
- var code = (OpCode)fields[i].GetValue(null)!;
- if (code.OpCodeType == OpCodeType.Nternal)
- continue;
-
- if (code.Size == 1)
- singleByteOpCode[code.Value] = code;
- else
- doubleByteOpCode[code.Value & 0xff] = code;
- }
- }
-
- static FieldInfo[] GetOpCodeFields() => typeof(OpCodes).GetFields(BindingFlags.Public | BindingFlags.Static);
}
-}
+
+
+ public ILReader(byte[] cil)
+ {
+ _cil = cil;
+ }
+
+ public OpCode OpCode { get; private set; }
+ public int MetadataToken { get; private set; }
+ public MemberInfo? Operand { get; private set; }
+
+ public bool Read(MethodBase methodInfo)
+ {
+ if (ptr < _cil.Length)
+ {
+ OpCode = ReadOpCode();
+ Operand = ReadOperand(OpCode, methodInfo);
+ return true;
+ }
+
+ return false;
+ }
+
+ private OpCode ReadOpCode()
+ {
+ var instruction = ReadByte();
+ if (instruction < 254)
+ return singleByteOpCode[instruction];
+ return doubleByteOpCode[ReadByte()];
+ }
+
+ private MemberInfo? ReadOperand(OpCode code, MethodBase methodInfo)
+ {
+ MetadataToken = 0;
+ int inlineLength;
+ switch (code.OperandType)
+ {
+ case OperandType.InlineMethod:
+ MetadataToken = ReadInt();
+ Type[]? methodArgs = null;
+ if (methodInfo.GetType() != typeof(ConstructorInfo) &&
+ !methodInfo.GetType().IsSubclassOf(typeof(ConstructorInfo)))
+ methodArgs = methodInfo.GetGenericArguments();
+ Type[]? typeArgs = null;
+ if (methodInfo.DeclaringType is not null) typeArgs = methodInfo.DeclaringType.GetGenericArguments();
+ try
+ {
+ return methodInfo.Module.ResolveMember(MetadataToken, typeArgs, methodArgs);
+ }
+ catch
+ {
+ // Can return System.ArgumentException : Token xxx is not a valid MemberInfo token in the scope of module xxx.dll
+ return null;
+ }
+
+ case OperandType.InlineNone:
+ inlineLength = 0;
+ break;
+
+ case OperandType.ShortInlineBrTarget:
+ case OperandType.ShortInlineVar:
+ case OperandType.ShortInlineI:
+ inlineLength = 1;
+ break;
+
+ case OperandType.InlineVar:
+ inlineLength = 2;
+ break;
+
+ case OperandType.InlineBrTarget:
+ case OperandType.InlineField:
+ case OperandType.InlineI:
+ case OperandType.InlineString:
+ case OperandType.InlineSig:
+ case OperandType.InlineSwitch:
+ case OperandType.InlineTok:
+ case OperandType.InlineType:
+ case OperandType.ShortInlineR:
+ inlineLength = 4;
+ break;
+
+ case OperandType.InlineI8:
+ case OperandType.InlineR:
+ inlineLength = 8;
+ break;
+
+ default:
+ return null;
+ }
+
+ for (var i = 0; i < inlineLength; i++) ReadByte();
+
+ return null;
+ }
+
+ private byte ReadByte()
+ {
+ return _cil[ptr++];
+ }
+
+ private int ReadInt()
+ {
+ var b1 = ReadByte();
+ var b2 = ReadByte();
+ var b3 = ReadByte();
+ var b4 = ReadByte();
+ return b1 | (b2 << 8) | (b3 << 16) | (b4 << 24);
+ }
+
+ private static FieldInfo[] GetOpCodeFields()
+ {
+ return typeof(OpCodes).GetFields(BindingFlags.Public | BindingFlags.Static);
+ }
+}
\ No newline at end of file
diff --git a/src/Ben.Demystifier/Internal/PortablePdbReader.cs b/src/Ben.Demystifier/Internal/PortablePdbReader.cs
index 5eab488..af7b861 100644
--- a/src/Ben.Demystifier/Internal/PortablePdbReader.cs
+++ b/src/Ben.Demystifier/Internal/PortablePdbReader.cs
@@ -1,136 +1,113 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-using System.Collections.Generic;
using System.IO;
-using System.Reflection;
using System.Reflection.Metadata;
using System.Reflection.Metadata.Ecma335;
using System.Reflection.PortableExecutable;
-namespace Ben.Demystifier.Internal
+namespace Ben.Demystifier.Internal;
+
+// Adapted from https://github.com/aspnet/Common/blob/dev/shared/Microsoft.Extensions.StackTrace.Sources/StackFrame/PortablePdbReader.cs
+internal class PortablePdbReader : IDisposable
{
- // Adapted from https://github.com/aspnet/Common/blob/dev/shared/Microsoft.Extensions.StackTrace.Sources/StackFrame/PortablePdbReader.cs
- internal class PortablePdbReader : IDisposable
+ private readonly Dictionary _cache = new(StringComparer.Ordinal);
+
+ public void Dispose()
{
- private readonly Dictionary _cache =
- new Dictionary(StringComparer.Ordinal);
+ foreach (var entry in _cache) entry.Value.Dispose();
- public void PopulateStackFrame(StackFrame frameInfo, MethodBase method, int IlOffset, out string fileName, out int row, out int column)
+ _cache.Clear();
+ }
+
+ public void PopulateStackFrame(StackFrame frameInfo, MethodBase method, int IlOffset, out string fileName,
+ out int row, out int column)
+ {
+ fileName = "";
+ row = 0;
+ column = 0;
+
+ if (method.Module.Assembly.IsDynamic) return;
+
+ var metadataReader = GetMetadataReader(method.Module.Assembly.Location);
+
+ if (metadataReader is null) return;
+
+ var methodToken = MetadataTokens.Handle(method.MetadataToken);
+
+ Debug.Assert(methodToken.Kind == HandleKind.MethodDefinition);
+
+ var handle = ((MethodDefinitionHandle)methodToken).ToDebugInformationHandle();
+
+ if (!handle.IsNil)
{
- fileName = "";
- row = 0;
- column = 0;
+ var methodDebugInfo = metadataReader.GetMethodDebugInformation(handle);
+ var sequencePoints = methodDebugInfo.GetSequencePoints();
+ SequencePoint? bestPointSoFar = null;
- if (method.Module.Assembly.IsDynamic)
+ foreach (var point in sequencePoints)
{
- return;
+ if (point.Offset > IlOffset) break;
+
+ if (point.StartLine != SequencePoint.HiddenLine) bestPointSoFar = point;
}
- var metadataReader = GetMetadataReader(method.Module.Assembly.Location);
-
- if (metadataReader == null)
+ if (bestPointSoFar.HasValue)
{
- return;
+ row = bestPointSoFar.Value.StartLine;
+ column = bestPointSoFar.Value.StartColumn;
+ fileName = metadataReader.GetString(metadataReader.GetDocument(bestPointSoFar.Value.Document).Name);
}
-
- var methodToken = MetadataTokens.Handle(method.MetadataToken);
-
- Debug.Assert(methodToken.Kind == HandleKind.MethodDefinition);
-
- var handle = ((MethodDefinitionHandle)methodToken).ToDebugInformationHandle();
-
- if (!handle.IsNil)
- {
- var methodDebugInfo = metadataReader.GetMethodDebugInformation(handle);
- var sequencePoints = methodDebugInfo.GetSequencePoints();
- SequencePoint? bestPointSoFar = null;
-
- foreach (var point in sequencePoints)
- {
- if (point.Offset > IlOffset)
- {
- break;
- }
-
- if (point.StartLine != SequencePoint.HiddenLine)
- {
- bestPointSoFar = point;
- }
- }
-
- if (bestPointSoFar.HasValue)
- {
- row = bestPointSoFar.Value.StartLine;
- column = bestPointSoFar.Value.StartColumn;
- fileName = metadataReader.GetString(metadataReader.GetDocument(bestPointSoFar.Value.Document).Name);
- }
- }
- }
-
- private MetadataReader? GetMetadataReader(string assemblyPath)
- {
- if (!_cache.TryGetValue(assemblyPath, out var provider) && provider is not null)
- {
- var pdbPath = GetPdbPath(assemblyPath);
-
- if (!string.IsNullOrEmpty(pdbPath) && File.Exists(pdbPath) && IsPortable(pdbPath!))
- {
- var pdbStream = File.OpenRead(pdbPath);
- provider = MetadataReaderProvider.FromPortablePdbStream(pdbStream);
- }
-
- _cache[assemblyPath] = provider;
- }
-
- return provider?.GetMetadataReader();
- }
-
- private static string? GetPdbPath(string assemblyPath)
- {
- if (string.IsNullOrEmpty(assemblyPath))
- {
- return null;
- }
-
- if (File.Exists(assemblyPath))
- {
- var peStream = File.OpenRead(assemblyPath);
-
- using var peReader = new PEReader(peStream);
- foreach (var entry in peReader.ReadDebugDirectory())
- {
- if (entry.Type == DebugDirectoryEntryType.CodeView)
- {
- var codeViewData = peReader.ReadCodeViewDebugDirectoryData(entry);
- var peDirectory = Path.GetDirectoryName(assemblyPath);
- return peDirectory is null
- ? null
- : Path.Combine(peDirectory, Path.GetFileName(codeViewData.Path));
- }
- }
- }
-
- return null;
- }
-
- private static bool IsPortable(string pdbPath)
- {
- using var pdbStream = File.OpenRead(pdbPath);
- return pdbStream.ReadByte() == 'B' &&
- pdbStream.ReadByte() == 'S' &&
- pdbStream.ReadByte() == 'J' &&
- pdbStream.ReadByte() == 'B';
- }
-
- public void Dispose()
- {
- foreach (var entry in _cache)
- {
- entry.Value?.Dispose();
- }
-
- _cache.Clear();
}
}
-}
+
+ private MetadataReader? GetMetadataReader(string assemblyPath)
+ {
+ if (!_cache.TryGetValue(assemblyPath, out var provider) && provider is not null)
+ {
+ var pdbPath = GetPdbPath(assemblyPath);
+
+ if (!string.IsNullOrEmpty(pdbPath) && File.Exists(pdbPath) && IsPortable(pdbPath!))
+ {
+ var pdbStream = File.OpenRead(pdbPath);
+ provider = MetadataReaderProvider.FromPortablePdbStream(pdbStream);
+ }
+
+ _cache[assemblyPath] = provider;
+ }
+
+ return provider?.GetMetadataReader();
+ }
+
+ private static string? GetPdbPath(string assemblyPath)
+ {
+ if (string.IsNullOrEmpty(assemblyPath)) return null;
+
+ if (File.Exists(assemblyPath))
+ {
+ var peStream = File.OpenRead(assemblyPath);
+
+ using var peReader = new PEReader(peStream);
+ foreach (var entry in peReader.ReadDebugDirectory())
+ if (entry.Type == DebugDirectoryEntryType.CodeView)
+ {
+ var codeViewData = peReader.ReadCodeViewDebugDirectoryData(entry);
+ var peDirectory = Path.GetDirectoryName(assemblyPath);
+ return peDirectory is null
+ ? null
+ : Path.Combine(peDirectory, Path.GetFileName(codeViewData.Path));
+ }
+ }
+
+ return null;
+ }
+
+ private static bool IsPortable(string pdbPath)
+ {
+ using var pdbStream = File.OpenRead(pdbPath);
+ return pdbStream.ReadByte() == 'B' &&
+ pdbStream.ReadByte() == 'S' &&
+ pdbStream.ReadByte() == 'J' &&
+ pdbStream.ReadByte() == 'B';
+ }
+}
\ No newline at end of file
diff --git a/src/Ben.Demystifier/Internal/ReflectionHelper.cs b/src/Ben.Demystifier/Internal/ReflectionHelper.cs
index 7f484d2..6e11b5a 100644
--- a/src/Ben.Demystifier/Internal/ReflectionHelper.cs
+++ b/src/Ben.Demystifier/Internal/ReflectionHelper.cs
@@ -1,62 +1,60 @@
// Copyright (c) Ben A Adams. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-using System.Collections.Generic;
-using System.Reflection;
using System.Threading;
-namespace Ben.Demystifier.Internal
+namespace Ben.Demystifier.Internal;
+
+///
+/// A helper class that contains utilities methods for dealing with reflection.
+///
+public static class ReflectionHelper
{
+ private static PropertyInfo? transformerNamesLazyPropertyInfo;
+
///
- /// A helper class that contains utilities methods for dealing with reflection.
+ /// Returns true if the is a value tuple type.
///
- public static class ReflectionHelper
+ public static bool IsValueTuple(this Type type)
{
- private static PropertyInfo? transformerNamesLazyPropertyInfo;
-
- ///
- /// Returns true if the is a value tuple type.
- ///
- public static bool IsValueTuple(this Type type)
- {
- return type.Namespace == "System" && type.Name.Contains("ValueTuple`");
- }
-
- ///
- /// Returns true if the given is of type TupleElementNameAttribute.
- ///
- ///
- /// To avoid compile-time dependency hell with System.ValueTuple, this method uses reflection and not checks statically that
- /// the given is TupleElementNameAttribute.
- ///
- public static bool IsTupleElementNameAttribute(this Attribute attribute)
- {
- var attributeType = attribute.GetType();
- return attributeType.Namespace == "System.Runtime.CompilerServices" &&
- attributeType.Name == "TupleElementNamesAttribute";
- }
-
- ///
- /// Returns 'TransformNames' property value from a given .
- ///
- ///
- /// To avoid compile-time dependency hell with System.ValueTuple, this method uses reflection
- /// instead of casting the attribute to a specific type.
- ///
- public static IList? GetTransformerNames(this Attribute attribute)
- {
- Debug.Assert(attribute.IsTupleElementNameAttribute());
-
- var propertyInfo = GetTransformNamesPropertyInfo(attribute.GetType());
- return propertyInfo?.GetValue(attribute) as IList;
- }
-
- private static PropertyInfo? GetTransformNamesPropertyInfo(Type attributeType)
- {
-#pragma warning disable 8634
- return LazyInitializer.EnsureInitialized(ref transformerNamesLazyPropertyInfo,
-#pragma warning restore 8634
- () => attributeType.GetProperty("TransformNames", BindingFlags.Instance | BindingFlags.Public)!);
- }
+ return type.Namespace == "System" && type.Name.Contains("ValueTuple`");
}
-}
+
+ ///
+ /// Returns true if the given is of type TupleElementNameAttribute.
+ ///
+ ///
+ /// To avoid compile-time dependency hell with System.ValueTuple, this method uses reflection and not checks statically
+ /// that
+ /// the given is TupleElementNameAttribute.
+ ///
+ public static bool IsTupleElementNameAttribute(this Attribute attribute)
+ {
+ var attributeType = attribute.GetType();
+ return attributeType.Namespace == "System.Runtime.CompilerServices" &&
+ attributeType.Name == "TupleElementNamesAttribute";
+ }
+
+ ///
+ /// Returns 'TransformNames' property value from a given .
+ ///
+ ///
+ /// To avoid compile-time dependency hell with System.ValueTuple, this method uses reflection
+ /// instead of casting the attribute to a specific type.
+ ///
+ public static IList? GetTransformerNames(this Attribute attribute)
+ {
+ Debug.Assert(attribute.IsTupleElementNameAttribute());
+
+ var propertyInfo = GetTransformNamesPropertyInfo(attribute.GetType());
+ return propertyInfo.GetValue(attribute) as IList;
+ }
+
+ private static PropertyInfo GetTransformNamesPropertyInfo(Type attributeType)
+ {
+#pragma warning disable 8634
+ return LazyInitializer.EnsureInitialized(ref transformerNamesLazyPropertyInfo,
+#pragma warning restore 8634
+ () => attributeType.GetProperty("TransformNames", BindingFlags.Instance | BindingFlags.Public)!);
+ }
+}
\ No newline at end of file
diff --git a/src/Ben.Demystifier/ResolvedMethod.cs b/src/Ben.Demystifier/ResolvedMethod.cs
index 1fb4fb8..31108da 100644
--- a/src/Ben.Demystifier/ResolvedMethod.cs
+++ b/src/Ben.Demystifier/ResolvedMethod.cs
@@ -2,171 +2,142 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Ben.Demystifier.Enumerable;
-using System.Reflection;
-using System.Text;
-namespace Ben.Demystifier
+namespace Ben.Demystifier;
+
+public class ResolvedMethod
{
- public class ResolvedMethod
+ public MethodBase? MethodBase { get; set; }
+
+ public Type? DeclaringType { get; set; }
+
+ public bool IsAsync { get; set; }
+
+ public bool IsLambda { get; set; }
+
+ public ResolvedParameter? ReturnParameter { get; set; }
+
+ public string? Name { get; set; }
+
+ public int? Ordinal { get; set; }
+
+ public string? GenericArguments { get; set; }
+
+ public Type[]? ResolvedGenericArguments { get; set; }
+
+ public MethodBase? SubMethodBase { get; set; }
+
+ public string? SubMethod { get; set; }
+
+ public EnumerableIList Parameters { get; set; }
+
+ public EnumerableIList SubMethodParameters { get; set; }
+ public int RecurseCount { get; internal set; }
+
+ internal bool IsSequentialEquivalent(ResolvedMethod obj)
{
- public MethodBase? MethodBase { get; set; }
+ return
+ IsAsync == obj.IsAsync &&
+ DeclaringType == obj.DeclaringType &&
+ Name == obj.Name &&
+ IsLambda == obj.IsLambda &&
+ Ordinal == obj.Ordinal &&
+ GenericArguments == obj.GenericArguments &&
+ SubMethod == obj.SubMethod;
+ }
- public Type? DeclaringType { get; set; }
-
- public bool IsAsync { get; set; }
+ public override string ToString() => AppendTo(new StringBuilder()).ToString();
- public bool IsLambda { get; set; }
+ public StringBuilder AppendTo(StringBuilder builder, bool fullName = true)
+ {
+ if (IsAsync) builder.Append("async ");
- public ResolvedParameter? ReturnParameter { get; set; }
-
- public string? Name { get; set; }
-
- public int? Ordinal { get; set; }
-
- public string? GenericArguments { get; set; }
-
- public Type[]? ResolvedGenericArguments { get; set; }
-
- public MethodBase? SubMethodBase { get; set; }
-
- public string? SubMethod { get; set; }
-
- public EnumerableIList Parameters { get; set; }
-
- public EnumerableIList SubMethodParameters { get; set; }
- public int RecurseCount { get; internal set; }
-
- internal bool IsSequentialEquivalent(ResolvedMethod obj)
+ if (ReturnParameter is not null)
{
- return
- IsAsync == obj.IsAsync &&
- DeclaringType == obj.DeclaringType &&
- Name == obj.Name &&
- IsLambda == obj.IsLambda &&
- Ordinal == obj.Ordinal &&
- GenericArguments == obj.GenericArguments &&
- SubMethod == obj.SubMethod;
+ ReturnParameter.Append(builder);
+ builder.Append(' ');
}
- public override string ToString() => Append(new StringBuilder()).ToString();
-
- public StringBuilder Append(StringBuilder builder)
- => Append(builder, true);
-
- public StringBuilder Append(StringBuilder builder, bool fullName)
+ if (DeclaringType is not null)
{
- if (IsAsync)
+ if (Name == ".ctor")
{
- builder.Append("async ");
+ if (string.IsNullOrEmpty(SubMethod) && !IsLambda)
+ builder.Append("new ");
+
+ AppendDeclaringTypeName(builder, fullName);
}
-
- if (ReturnParameter != null)
+ else if (Name == ".cctor")
{
- ReturnParameter.Append(builder);
- builder.Append(" ");
- }
-
- if (DeclaringType != null)
- {
-
- if (Name == ".ctor")
- {
- if (string.IsNullOrEmpty(SubMethod) && !IsLambda)
- builder.Append("new ");
-
- AppendDeclaringTypeName(builder, fullName);
- }
- else if (Name == ".cctor")
- {
- builder.Append("static ");
- AppendDeclaringTypeName(builder, fullName);
- }
- else
- {
- AppendDeclaringTypeName(builder, fullName)
- .Append(".")
- .Append(Name);
- }
+ builder.Append("static ");
+ AppendDeclaringTypeName(builder, fullName);
}
else
{
- builder.Append(Name);
+ AppendDeclaringTypeName(builder, fullName)
+ .Append('.')
+ .Append(Name);
}
- builder.Append(GenericArguments);
+ }
+ else builder.Append(Name);
- builder.Append("(");
- if (MethodBase != null)
+ builder.Append(GenericArguments);
+
+ builder.Append('(');
+ if (MethodBase is not null)
+ {
+ var isFirst = true;
+ foreach (var param in Parameters)
+ {
+ if (isFirst)
+ isFirst = false;
+ else builder.Append(", ");
+ param.Append(builder);
+ }
+ }
+ else builder.Append('?');
+
+ builder.Append(')');
+
+ if (!string.IsNullOrEmpty(SubMethod) || IsLambda)
+ {
+ builder.Append('+');
+ builder.Append(SubMethod);
+ builder.Append('(');
+ if (SubMethodBase is not null)
{
var isFirst = true;
- foreach(var param in Parameters)
+ foreach (var param in SubMethodParameters)
{
if (isFirst)
- {
isFirst = false;
- }
- else
- {
- builder.Append(", ");
- }
+ else builder.Append(", ");
param.Append(builder);
}
}
- else
- {
- builder.Append("?");
- }
- builder.Append(")");
+ else builder.Append('?');
- if (!string.IsNullOrEmpty(SubMethod) || IsLambda)
+ builder.Append(')');
+ if (IsLambda)
{
- builder.Append("+");
- builder.Append(SubMethod);
- builder.Append("(");
- if (SubMethodBase != null)
- {
- var isFirst = true;
- foreach (var param in SubMethodParameters)
- {
- if (isFirst)
- {
- isFirst = false;
- }
- else
- {
- builder.Append(", ");
- }
- param.Append(builder);
- }
- }
- else
- {
- builder.Append("?");
- }
- builder.Append(")");
- if (IsLambda)
- {
- builder.Append(" => { }");
+ builder.Append(" => { }");
- if (Ordinal.HasValue)
- {
- builder.Append(" [");
- builder.Append(Ordinal);
- builder.Append("]");
- }
+ if (Ordinal.HasValue)
+ {
+ builder.Append(" [");
+ builder.Append(Ordinal);
+ builder.Append(']');
}
}
-
- if (RecurseCount > 0)
- {
- builder.Append($" x {RecurseCount + 1:0}");
- }
-
- return builder;
}
- private StringBuilder AppendDeclaringTypeName(StringBuilder builder, bool fullName = true)
- {
- return DeclaringType != null ? builder.AppendTypeDisplayName(DeclaringType, fullName: fullName, includeGenericParameterNames: true) : builder;
- }
+ if (RecurseCount > 0) builder.Append($" x {RecurseCount + 1:0}");
+
+ return builder;
}
-}
+
+ private StringBuilder AppendDeclaringTypeName(StringBuilder builder, bool fullName = true)
+ {
+ return DeclaringType is not null ? builder.AppendTypeDisplayName(DeclaringType, fullName, true) : builder;
+ }
+}
\ No newline at end of file
diff --git a/src/Ben.Demystifier/ResolvedParameter.cs b/src/Ben.Demystifier/ResolvedParameter.cs
index 9433c85..7208dfc 100644
--- a/src/Ben.Demystifier/ResolvedParameter.cs
+++ b/src/Ben.Demystifier/ResolvedParameter.cs
@@ -1,59 +1,49 @@
// Copyright (c) Ben A Adams. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-using System.Text;
+namespace Ben.Demystifier;
-namespace Ben.Demystifier
+public class ResolvedParameter
{
- public class ResolvedParameter
+ public ResolvedParameter(Type resolvedType)
{
- public string? Name { get; set; }
-
- public Type ResolvedType { get; set; }
-
- public string? Prefix { get; set; }
- public bool IsDynamicType { get; set; }
-
- public ResolvedParameter(Type resolvedType) => ResolvedType = resolvedType;
-
- public override string ToString() => Append(new StringBuilder()).ToString();
-
- public StringBuilder Append(StringBuilder sb)
- {
- if (ResolvedType.Assembly.ManifestModule.Name == "FSharp.Core.dll" && ResolvedType.Name == "Unit")
- return sb;
-
- if (!string.IsNullOrEmpty(Prefix))
- {
- sb.Append(Prefix)
- .Append(" ");
- }
-
- if (IsDynamicType)
- {
- sb.Append("dynamic");
- }
- else if (ResolvedType != null)
- {
- AppendTypeName(sb);
- }
- else
- {
- sb.Append("?");
- }
-
- if (!string.IsNullOrEmpty(Name))
- {
- sb.Append(" ")
- .Append(Name);
- }
-
- return sb;
- }
-
- protected virtual void AppendTypeName(StringBuilder sb)
- {
- sb.AppendTypeDisplayName(ResolvedType, fullName: false, includeGenericParameterNames: true);
- }
+ ResolvedType = resolvedType;
}
-}
+
+ public string? Name { get; set; }
+
+ public Type ResolvedType { get; set; }
+
+ public string? Prefix { get; set; }
+ public bool IsDynamicType { get; set; }
+
+ public override string ToString()
+ {
+ return Append(new StringBuilder()).ToString();
+ }
+
+ public StringBuilder Append(StringBuilder sb)
+ {
+ if (ResolvedType.Assembly.ManifestModule.Name == "FSharp.Core.dll" && ResolvedType.Name == "Unit")
+ return sb;
+
+ if (!string.IsNullOrEmpty(Prefix))
+ sb.Append(Prefix)
+ .Append(' ');
+
+ if (IsDynamicType)
+ sb.Append("dynamic");
+ else AppendTypeName(sb);
+
+ if (!string.IsNullOrEmpty(Name))
+ sb.Append(' ')
+ .Append(Name);
+
+ return sb;
+ }
+
+ protected virtual void AppendTypeName(StringBuilder sb)
+ {
+ sb.AppendTypeDisplayName(ResolvedType, false, true);
+ }
+}
\ No newline at end of file
diff --git a/src/Ben.Demystifier/StringBuilderExtentions.cs b/src/Ben.Demystifier/StringBuilderExtentions.cs
index 55d01e2..196dd8c 100644
--- a/src/Ben.Demystifier/StringBuilderExtentions.cs
+++ b/src/Ben.Demystifier/StringBuilderExtentions.cs
@@ -2,55 +2,42 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Ben.Demystifier.Enumerable;
-using System.Text;
-namespace Ben.Demystifier
+namespace Ben.Demystifier;
+
+public static class StringBuilderExtentions
{
- public static class StringBuilderExtentions
+ public static StringBuilder AppendDemystified(this StringBuilder builder, Exception exception)
{
- public static StringBuilder AppendDemystified(this StringBuilder builder, Exception exception)
+ try
{
- try
- {
- var stackTrace = new EnhancedStackTrace(exception);
+ var stackTrace = new EnhancedStackTrace(exception);
- builder.Append(exception.GetType());
- if (!string.IsNullOrEmpty(exception.Message))
- {
- builder.Append(": ").Append(exception.Message);
- }
- builder.Append(Environment.NewLine);
+ builder.Append(exception.GetType());
+ if (!string.IsNullOrEmpty(exception.Message)) builder.Append(": ").Append(exception.Message);
+ builder.Append(Environment.NewLine);
- if (stackTrace.FrameCount > 0)
- {
- stackTrace.Append(builder);
- }
+ if (stackTrace.FrameCount > 0) stackTrace.AppendTo(builder);
- if (exception is AggregateException aggEx)
- {
- foreach (var ex in EnumerableIList.Create(aggEx.InnerExceptions))
- {
- builder.AppendInnerException(ex);
- }
- }
+ if (exception is AggregateException aggEx)
+ foreach (var ex in EnumerableIList.Create(aggEx.InnerExceptions))
+ builder.AppendInnerException(ex);
- if (exception.InnerException != null)
- {
- builder.AppendInnerException(exception.InnerException);
- }
- }
- catch
- {
- // Processing exceptions shouldn't throw exceptions; if it fails
- }
-
- return builder;
+ if (exception.InnerException is not null) builder.AppendInnerException(exception.InnerException);
+ }
+ catch
+ {
+ // Processing exceptions shouldn't throw exceptions; if it fails
}
- private static void AppendInnerException(this StringBuilder builder, Exception exception)
- => builder.Append(" ---> ")
- .AppendDemystified(exception)
- .AppendLine()
- .Append(" --- End of inner exception stack trace ---");
+ return builder;
}
-}
+
+ private static void AppendInnerException(this StringBuilder builder, Exception exception)
+ {
+ builder.Append(" ---> ")
+ .AppendDemystified(exception)
+ .AppendLine()
+ .Append(" --- End of inner exception stack trace ---");
+ }
+}
\ No newline at end of file
diff --git a/src/Ben.Demystifier/TypeNameHelper.cs b/src/Ben.Demystifier/TypeNameHelper.cs
index 8e36e35..2c44768 100644
--- a/src/Ben.Demystifier/TypeNameHelper.cs
+++ b/src/Ben.Demystifier/TypeNameHelper.cs
@@ -1,218 +1,192 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-using System.Collections.Generic;
-using System.Text;
+namespace Ben.Demystifier;
-namespace Ben.Demystifier
+// Adapted from https://github.com/aspnet/Common/blob/dev/shared/Microsoft.Extensions.TypeNameHelper.Sources/TypeNameHelper.cs
+public static class TypeNameHelper
{
- // Adapted from https://github.com/aspnet/Common/blob/dev/shared/Microsoft.Extensions.TypeNameHelper.Sources/TypeNameHelper.cs
- public static class TypeNameHelper
+ public static readonly Dictionary BuiltInTypeNames = new()
{
- public static readonly Dictionary BuiltInTypeNames = new Dictionary
- {
- { typeof(void), "void" },
- { typeof(bool), "bool" },
- { typeof(byte), "byte" },
- { typeof(char), "char" },
- { typeof(decimal), "decimal" },
- { typeof(double), "double" },
- { typeof(float), "float" },
- { typeof(int), "int" },
- { typeof(long), "long" },
- { typeof(object), "object" },
- { typeof(sbyte), "sbyte" },
- { typeof(short), "short" },
- { typeof(string), "string" },
- { typeof(uint), "uint" },
- { typeof(ulong), "ulong" },
- { typeof(ushort), "ushort" }
- };
-
- public static readonly Dictionary FSharpTypeNames = new Dictionary
- {
- { "Unit", "void" },
- { "FSharpOption", "Option" },
- { "FSharpAsync", "Async" },
- { "FSharpOption`1", "Option" },
- { "FSharpAsync`1", "Async" }
- };
+ { typeof(void), "void" },
+ { typeof(bool), "bool" },
+ { typeof(byte), "byte" },
+ { typeof(char), "char" },
+ { typeof(decimal), "decimal" },
+ { typeof(double), "double" },
+ { typeof(float), "float" },
+ { typeof(int), "int" },
+ { typeof(long), "long" },
+ { typeof(object), "object" },
+ { typeof(sbyte), "sbyte" },
+ { typeof(short), "short" },
+ { typeof(string), "string" },
+ { typeof(uint), "uint" },
+ { typeof(ulong), "ulong" },
+ { typeof(ushort), "ushort" }
+ };
- ///
- /// Pretty print a type name.
- ///
- /// The .
- /// true to print a fully qualified name.
- /// true to include generic parameter names.
- /// The pretty printed type name.
- public static string GetTypeDisplayName(Type type, bool fullName = true, bool includeGenericParameterNames = false)
+ public static readonly Dictionary FSharpTypeNames = new()
+ {
+ { "Unit", "void" },
+ { "FSharpOption", "Option" },
+ { "FSharpAsync", "Async" },
+ { "FSharpOption`1", "Option" },
+ { "FSharpAsync`1", "Async" }
+ };
+
+ ///
+ /// Pretty print a type name.
+ ///
+ /// The .
+ /// true to print a fully qualified name.
+ /// true to include generic parameter names.
+ /// The pretty printed type name.
+ public static string GetTypeDisplayName(Type type, bool fullName = true, bool includeGenericParameterNames = false)
+ {
+ var builder = new StringBuilder();
+ ProcessType(builder, type, new DisplayNameOptions(fullName, includeGenericParameterNames));
+ return builder.ToString();
+ }
+
+ public static StringBuilder AppendTypeDisplayName(this StringBuilder builder, Type type, bool fullName = true,
+ bool includeGenericParameterNames = false)
+ {
+ ProcessType(builder, type, new DisplayNameOptions(fullName, includeGenericParameterNames));
+ return builder;
+ }
+
+ ///
+ /// Returns a name of given generic type without '`'.
+ ///
+ public static string GetTypeNameForGenericType(Type type)
+ {
+ if (!type.IsGenericType) throw new ArgumentException("The given type should be generic", nameof(type));
+
+ var genericPartIndex = type.Name.IndexOf('`');
+
+ return genericPartIndex >= 0 ? type.Name.Substring(0, genericPartIndex) : type.Name;
+ }
+
+ private static void ProcessType(StringBuilder builder, Type type, DisplayNameOptions options)
+ {
+ if (type.IsGenericType)
{
- var builder = new StringBuilder();
- ProcessType(builder, type, new DisplayNameOptions(fullName, includeGenericParameterNames));
- return builder.ToString();
- }
-
- public static StringBuilder AppendTypeDisplayName(this StringBuilder builder, Type type, bool fullName = true, bool includeGenericParameterNames = false)
- {
- ProcessType(builder, type, new DisplayNameOptions(fullName, includeGenericParameterNames));
- return builder;
- }
-
- ///
- /// Returns a name of given generic type without '`'.
- ///
- public static string GetTypeNameForGenericType(Type type)
- {
- if (!type.IsGenericType)
+ var underlyingType = Nullable.GetUnderlyingType(type);
+ if (underlyingType is not null)
{
- throw new ArgumentException("The given type should be generic", nameof(type));
- }
-
- var genericPartIndex = type.Name.IndexOf('`');
-
- return (genericPartIndex >= 0) ? type.Name.Substring(0, genericPartIndex) : type.Name;
- }
-
- private static void ProcessType(StringBuilder builder, Type type, DisplayNameOptions options)
- {
- if (type.IsGenericType)
- {
- var underlyingType = Nullable.GetUnderlyingType(type);
- if (underlyingType != null)
- {
- ProcessType(builder, underlyingType, options);
- builder.Append('?');
- }
- else
- {
- var genericArguments = type.GetGenericArguments();
- ProcessGenericType(builder, type, genericArguments, genericArguments.Length, options);
- }
- }
- else if (type.IsArray)
- {
- ProcessArrayType(builder, type, options);
- }
- else if (BuiltInTypeNames.TryGetValue(type, out var builtInName))
- {
- builder.Append(builtInName);
- }
- else if (type.Namespace == nameof(System))
- {
- builder.Append(type.Name);
- }
- else if (type.Assembly.ManifestModule.Name == "FSharp.Core.dll"
- && FSharpTypeNames.TryGetValue(type.Name, out builtInName))
- {
- builder.Append(builtInName);
- }
- else if (type.IsGenericParameter)
- {
- if (options.IncludeGenericParameterNames)
- {
- builder.Append(type.Name);
- }
+ ProcessType(builder, underlyingType, options);
+ builder.Append('?');
}
else
{
- builder.Append(options.FullName ? type.FullName ?? type.Name : type.Name);
+ var genericArguments = type.GetGenericArguments();
+ ProcessGenericType(builder, type, genericArguments, genericArguments.Length, options);
}
}
-
- private static void ProcessArrayType(StringBuilder builder, Type type, DisplayNameOptions options)
+ else if (type.IsArray)
{
- var innerType = type;
- while (innerType.IsArray)
- {
- if (innerType.GetElementType() is { } inner)
- {
- innerType = inner;
- }
- }
-
- ProcessType(builder, innerType, options);
-
- while (type.IsArray)
- {
- builder.Append('[');
- builder.Append(',', type.GetArrayRank() - 1);
- builder.Append(']');
- if (type.GetElementType() is not { } elementType)
- {
- break;
- }
- type = elementType;
- }
+ ProcessArrayType(builder, type, options);
}
-
- private static void ProcessGenericType(StringBuilder builder, Type type, Type[] genericArguments, int length, DisplayNameOptions options)
+ else if (BuiltInTypeNames.TryGetValue(type, out var builtInName))
{
- var offset = 0;
- if (type.IsNested && type.DeclaringType is not null)
- {
- offset = type.DeclaringType.GetGenericArguments().Length;
- }
-
- if (options.FullName)
- {
- if (type.IsNested && type.DeclaringType is not null)
- {
- ProcessGenericType(builder, type.DeclaringType, genericArguments, offset, options);
- builder.Append('+');
- }
- else if (!string.IsNullOrEmpty(type.Namespace))
- {
- builder.Append(type.Namespace);
- builder.Append('.');
- }
- }
-
- var genericPartIndex = type.Name.IndexOf('`');
- if (genericPartIndex <= 0)
- {
- builder.Append(type.Name);
- return;
- }
-
- if (type.Assembly.ManifestModule.Name == "FSharp.Core.dll"
- && FSharpTypeNames.TryGetValue(type.Name, out var builtInName))
- {
- builder.Append(builtInName);
- }
- else
- {
- builder.Append(type.Name, 0, genericPartIndex);
- }
-
- builder.Append('<');
- for (var i = offset; i < length; i++)
- {
- ProcessType(builder, genericArguments[i], options);
- if (i + 1 == length)
- {
- continue;
- }
-
- builder.Append(',');
- if (options.IncludeGenericParameterNames || !genericArguments[i + 1].IsGenericParameter)
- {
- builder.Append(' ');
- }
- }
- builder.Append('>');
+ builder.Append(builtInName);
}
-
- private struct DisplayNameOptions
+ else if (type.Namespace == nameof(System))
{
- public DisplayNameOptions(bool fullName, bool includeGenericParameterNames)
- {
- FullName = fullName;
- IncludeGenericParameterNames = includeGenericParameterNames;
- }
-
- public bool FullName { get; }
-
- public bool IncludeGenericParameterNames { get; }
+ builder.Append(type.Name);
+ }
+ else if (type.Assembly.ManifestModule.Name == "FSharp.Core.dll"
+ && FSharpTypeNames.TryGetValue(type.Name, out builtInName))
+ {
+ builder.Append(builtInName);
+ }
+ else if (type.IsGenericParameter)
+ {
+ if (options.IncludeGenericParameterNames) builder.Append(type.Name);
+ }
+ else
+ {
+ builder.Append(options.FullName ? type.FullName ?? type.Name : type.Name);
}
}
-}
+
+ private static void ProcessArrayType(StringBuilder builder, Type type, DisplayNameOptions options)
+ {
+ var innerType = type;
+ while (innerType.IsArray)
+ if (innerType.GetElementType() is { } inner)
+ innerType = inner;
+
+ ProcessType(builder, innerType, options);
+
+ while (type.IsArray)
+ {
+ builder.Append('[');
+ builder.Append(',', type.GetArrayRank() - 1);
+ builder.Append(']');
+ if (type.GetElementType() is not { } elementType) break;
+ type = elementType;
+ }
+ }
+
+ private static void ProcessGenericType(StringBuilder builder, Type type, Type[] genericArguments, int length,
+ DisplayNameOptions options)
+ {
+ var offset = 0;
+ if (type.IsNested && type.DeclaringType is not null) offset = type.DeclaringType.GetGenericArguments().Length;
+
+ if (options.FullName)
+ {
+ if (type.IsNested && type.DeclaringType is not null)
+ {
+ ProcessGenericType(builder, type.DeclaringType, genericArguments, offset, options);
+ builder.Append('+');
+ }
+ else if (!string.IsNullOrEmpty(type.Namespace))
+ {
+ builder.Append(type.Namespace);
+ builder.Append('.');
+ }
+ }
+
+ var genericPartIndex = type.Name.IndexOf('`');
+ if (genericPartIndex <= 0)
+ {
+ builder.Append(type.Name);
+ return;
+ }
+
+ if (type.Assembly.ManifestModule.Name == "FSharp.Core.dll"
+ && FSharpTypeNames.TryGetValue(type.Name, out var builtInName))
+ builder.Append(builtInName);
+ else
+ builder.Append(type.Name, 0, genericPartIndex);
+
+ builder.Append('<');
+ for (var i = offset; i < length; i++)
+ {
+ ProcessType(builder, genericArguments[i], options);
+ if (i + 1 == length) continue;
+
+ builder.Append(',');
+ if (options.IncludeGenericParameterNames || !genericArguments[i + 1].IsGenericParameter)
+ builder.Append(' ');
+ }
+
+ builder.Append('>');
+ }
+
+ private struct DisplayNameOptions
+ {
+ public DisplayNameOptions(bool fullName, bool includeGenericParameterNames)
+ {
+ FullName = fullName;
+ IncludeGenericParameterNames = includeGenericParameterNames;
+ }
+
+ public bool FullName { get; }
+
+ public bool IncludeGenericParameterNames { get; }
+ }
+}
\ No newline at end of file
diff --git a/src/Ben.Demystifier/ValueTupleResolvedParameter.cs b/src/Ben.Demystifier/ValueTupleResolvedParameter.cs
index 26e0daf..5037e26 100644
--- a/src/Ben.Demystifier/ValueTupleResolvedParameter.cs
+++ b/src/Ben.Demystifier/ValueTupleResolvedParameter.cs
@@ -1,68 +1,58 @@
// Copyright (c) Ben A Adams. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-using System.Collections.Generic;
using Ben.Demystifier.Internal;
-using System.Text;
-namespace Ben.Demystifier
+namespace Ben.Demystifier;
+
+public class ValueTupleResolvedParameter : ResolvedParameter
{
- public class ValueTupleResolvedParameter : ResolvedParameter
+ public ValueTupleResolvedParameter(Type resolvedType, IList tupleNames)
+ : base(resolvedType)
{
- public IList TupleNames { get; }
+ TupleNames = tupleNames;
+ }
- public ValueTupleResolvedParameter(Type resolvedType, IList tupleNames)
- : base(resolvedType)
- => TupleNames = tupleNames;
+ public IList TupleNames { get; }
- protected override void AppendTypeName(StringBuilder sb)
+ protected override void AppendTypeName(StringBuilder sb)
+ {
+ if (ResolvedType is not null)
{
- if (ResolvedType is not null)
+ if (ResolvedType.IsValueTuple())
{
- if (ResolvedType.IsValueTuple())
- {
- AppendValueTupleParameterName(sb, ResolvedType);
- }
- else
- {
- // Need to unwrap the first generic argument first.
- sb.Append(TypeNameHelper.GetTypeNameForGenericType(ResolvedType));
- sb.Append("<");
- AppendValueTupleParameterName(sb, ResolvedType.GetGenericArguments()[0]);
- sb.Append(">");
- }
+ AppendValueTupleParameterName(sb, ResolvedType);
}
- }
-
- private void AppendValueTupleParameterName(StringBuilder sb, Type parameterType)
- {
- sb.Append("(");
- var args = parameterType.GetGenericArguments();
- for (var i = 0; i < args.Length; i++)
+ else
{
- if (i > 0)
- {
- sb.Append(", ");
- }
-
- sb.AppendTypeDisplayName(args[i], fullName: false, includeGenericParameterNames: true);
-
- if (i >= TupleNames.Count)
- {
- continue;
- }
-
- var argName = TupleNames[i];
- if (argName == null)
- {
- continue;
- }
-
- sb.Append(" ");
- sb.Append(argName);
+ // Need to unwrap the first generic argument first.
+ sb.Append(TypeNameHelper.GetTypeNameForGenericType(ResolvedType));
+ sb.Append("<");
+ AppendValueTupleParameterName(sb, ResolvedType.GetGenericArguments()[0]);
+ sb.Append(">");
}
-
- sb.Append(")");
}
}
-}
+
+ private void AppendValueTupleParameterName(StringBuilder sb, Type parameterType)
+ {
+ sb.Append('(');
+ var args = parameterType.GetGenericArguments();
+ for (var i = 0; i < args.Length; i++)
+ {
+ if (i > 0) sb.Append(", ");
+
+ sb.AppendTypeDisplayName(args[i], false, true);
+
+ if (i >= TupleNames.Count) continue;
+
+ var argName = TupleNames[i];
+ if (argName is null) continue;
+
+ sb.Append(' ');
+ sb.Append(argName);
+ }
+
+ sb.Append(')');
+ }
+}
\ No newline at end of file