Allow demystifier to add strings to existing StringBuilder (#73)
This commit is contained in:
parent
aa10921687
commit
7aa753d5c7
@ -171,11 +171,10 @@ namespace System.Diagnostics
|
|||||||
// ResolveStateMachineMethod may have set declaringType to null
|
// ResolveStateMachineMethod may have set declaringType to null
|
||||||
if (type != null)
|
if (type != null)
|
||||||
{
|
{
|
||||||
var declaringTypeName = TypeNameHelper.GetTypeDisplayName(type, fullName: true, includeGenericParameterNames: true);
|
methodDisplayInfo.DeclaringType = type;
|
||||||
methodDisplayInfo.DeclaringTypeName = declaringTypeName;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (method is System.Reflection.MethodInfo mi)
|
if (method is MethodInfo mi)
|
||||||
{
|
{
|
||||||
var returnParameter = mi.ReturnParameter;
|
var returnParameter = mi.ReturnParameter;
|
||||||
if (returnParameter != null)
|
if (returnParameter != null)
|
||||||
@ -188,7 +187,6 @@ namespace System.Diagnostics
|
|||||||
{
|
{
|
||||||
Prefix = "",
|
Prefix = "",
|
||||||
Name = "",
|
Name = "",
|
||||||
Type = TypeNameHelper.GetTypeDisplayName(mi.ReturnType, fullName: false, includeGenericParameterNames: true).ToString(),
|
|
||||||
ResolvedType = mi.ReturnType,
|
ResolvedType = mi.ReturnType,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -540,7 +538,6 @@ namespace System.Diagnostics
|
|||||||
{
|
{
|
||||||
var parameterType = parameter.ParameterType;
|
var parameterType = parameter.ParameterType;
|
||||||
var prefix = GetPrefix(parameter, parameterType);
|
var prefix = GetPrefix(parameter, parameterType);
|
||||||
var parameterTypeString = "?";
|
|
||||||
|
|
||||||
if (parameterType == null)
|
if (parameterType == null)
|
||||||
{
|
{
|
||||||
@ -548,7 +545,6 @@ namespace System.Diagnostics
|
|||||||
{
|
{
|
||||||
Prefix = prefix,
|
Prefix = prefix,
|
||||||
Name = parameter.Name,
|
Name = parameter.Name,
|
||||||
Type = parameterTypeString,
|
|
||||||
ResolvedType = parameterType,
|
ResolvedType = parameterType,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -572,40 +568,22 @@ namespace System.Diagnostics
|
|||||||
parameterType = parameterType.GetElementType();
|
parameterType = parameterType.GetElementType();
|
||||||
}
|
}
|
||||||
|
|
||||||
parameterTypeString = TypeNameHelper.GetTypeDisplayName(parameterType, fullName: false, includeGenericParameterNames: true);
|
|
||||||
|
|
||||||
return new ResolvedParameter
|
return new ResolvedParameter
|
||||||
{
|
{
|
||||||
Prefix = prefix,
|
Prefix = prefix,
|
||||||
Name = parameter.Name,
|
Name = parameter.Name,
|
||||||
Type = parameterTypeString,
|
|
||||||
ResolvedType = parameterType,
|
ResolvedType = parameterType,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ResolvedParameter GetValueTupleParameter(IList<string> tupleNames, string prefix, string name, Type parameterType)
|
private static ResolvedParameter GetValueTupleParameter(IList<string> tupleNames, string prefix, string name, Type parameterType)
|
||||||
{
|
{
|
||||||
string typeName;
|
return new ValueTupleResolvedParameter
|
||||||
|
|
||||||
if (parameterType.IsValueTuple())
|
|
||||||
{
|
|
||||||
typeName = GetValueTupleParameterName(tupleNames, parameterType);
|
|
||||||
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Need to unwrap the first generic argument first.
|
|
||||||
var genericTypeName = TypeNameHelper.GetTypeNameForGenericType(parameterType);
|
|
||||||
var valueTupleFullName = GetValueTupleParameterName(tupleNames, parameterType.GetGenericArguments()[0]);
|
|
||||||
typeName = $"{genericTypeName}<{valueTupleFullName}>";
|
|
||||||
}
|
|
||||||
|
|
||||||
return new ResolvedParameter
|
|
||||||
{
|
{
|
||||||
|
TupleNames = tupleNames,
|
||||||
Prefix = prefix,
|
Prefix = prefix,
|
||||||
Name = name,
|
Name = name,
|
||||||
Type = typeName,
|
ResolvedType = parameterType
|
||||||
ResolvedType = parameterType,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -4,6 +4,7 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Generic.Enumerable;
|
using System.Collections.Generic.Enumerable;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
namespace System.Diagnostics
|
namespace System.Diagnostics
|
||||||
{
|
{
|
||||||
@ -12,27 +13,16 @@ namespace System.Diagnostics
|
|||||||
{
|
{
|
||||||
private static readonly FieldInfo stackTraceString = typeof(Exception).GetField("_stackTraceString", BindingFlags.Instance | BindingFlags.NonPublic);
|
private static readonly FieldInfo stackTraceString = typeof(Exception).GetField("_stackTraceString", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||||
|
|
||||||
public static T Demystify<T>(this T exception) where T : Exception
|
|
||||||
=> Demystify(exception, originalStacksTracker: null);
|
|
||||||
|
|
||||||
private static string GetStackTracesString(this Exception exception)
|
|
||||||
=> (string)stackTraceString.GetValue(exception);
|
|
||||||
|
|
||||||
private static void SetStackTracesString(this Exception exception, string value)
|
private static void SetStackTracesString(this Exception exception, string value)
|
||||||
=> stackTraceString.SetValue(exception, value);
|
=> stackTraceString.SetValue(exception, value);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Demystifies the given <paramref name="exception"/> and tracks the original stack traces for the whole exception tree.
|
/// Demystifies the given <paramref name="exception"/> and tracks the original stack traces for the whole exception tree.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private static T Demystify<T>(this T exception, Dictionary<Exception, string> originalStacksTracker) where T : Exception
|
public static T Demystify<T>(this T exception) where T : Exception
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (originalStacksTracker?.ContainsKey(exception) == false)
|
|
||||||
{
|
|
||||||
originalStacksTracker[exception] = exception.GetStackTracesString();
|
|
||||||
}
|
|
||||||
|
|
||||||
var stackTrace = new EnhancedStackTrace(exception);
|
var stackTrace = new EnhancedStackTrace(exception);
|
||||||
|
|
||||||
if (stackTrace.FrameCount > 0)
|
if (stackTrace.FrameCount > 0)
|
||||||
@ -44,11 +34,11 @@ namespace System.Diagnostics
|
|||||||
{
|
{
|
||||||
foreach (var ex in EnumerableIList.Create(aggEx.InnerExceptions))
|
foreach (var ex in EnumerableIList.Create(aggEx.InnerExceptions))
|
||||||
{
|
{
|
||||||
ex.Demystify(originalStacksTracker);
|
ex.Demystify();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
exception.InnerException?.Demystify(originalStacksTracker);
|
exception.InnerException?.Demystify();
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
@ -69,27 +59,6 @@ namespace System.Diagnostics
|
|||||||
/// </remarks>
|
/// </remarks>
|
||||||
[Contracts.Pure]
|
[Contracts.Pure]
|
||||||
public static string ToStringDemystified(this Exception exception)
|
public static string ToStringDemystified(this Exception exception)
|
||||||
{
|
=> new StringBuilder().AppendDemystified(exception).ToString();
|
||||||
try
|
|
||||||
{
|
|
||||||
var originalStacks = new Dictionary<Exception, string>();
|
|
||||||
exception.Demystify(originalStacks);
|
|
||||||
|
|
||||||
var result = exception.ToString();
|
|
||||||
|
|
||||||
foreach (var kvp in originalStacks)
|
|
||||||
{
|
|
||||||
kvp.Key.SetStackTracesString(kvp.Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
// Processing exceptions shouldn't throw exceptions; if it fails
|
|
||||||
}
|
|
||||||
|
|
||||||
return exception.ToString();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,7 +11,7 @@ namespace System.Diagnostics
|
|||||||
{
|
{
|
||||||
public MethodBase MethodBase { get; set; }
|
public MethodBase MethodBase { get; set; }
|
||||||
|
|
||||||
public string DeclaringTypeName { get; set; }
|
public Type DeclaringType { get; set; }
|
||||||
|
|
||||||
public bool IsAsync { get; set; }
|
public bool IsAsync { get; set; }
|
||||||
|
|
||||||
@ -39,11 +39,9 @@ namespace System.Diagnostics
|
|||||||
|
|
||||||
internal StringBuilder Append(StringBuilder builder)
|
internal StringBuilder Append(StringBuilder builder)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (IsAsync)
|
if (IsAsync)
|
||||||
{
|
{
|
||||||
builder
|
builder.Append("async ");
|
||||||
.Append("async ");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ReturnParameter != null)
|
if (ReturnParameter != null)
|
||||||
@ -52,7 +50,7 @@ namespace System.Diagnostics
|
|||||||
builder.Append(" ");
|
builder.Append(" ");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(DeclaringTypeName))
|
if (DeclaringType != null)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (Name == ".ctor")
|
if (Name == ".ctor")
|
||||||
@ -60,17 +58,16 @@ namespace System.Diagnostics
|
|||||||
if (string.IsNullOrEmpty(SubMethod) && !IsLambda)
|
if (string.IsNullOrEmpty(SubMethod) && !IsLambda)
|
||||||
builder.Append("new ");
|
builder.Append("new ");
|
||||||
|
|
||||||
builder.Append(DeclaringTypeName);
|
AppendDeclaringTypeName(builder);
|
||||||
}
|
}
|
||||||
else if (Name == ".cctor")
|
else if (Name == ".cctor")
|
||||||
{
|
{
|
||||||
builder.Append("static ");
|
builder.Append("static ");
|
||||||
builder.Append(DeclaringTypeName);
|
AppendDeclaringTypeName(builder);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
builder
|
AppendDeclaringTypeName(builder)
|
||||||
.Append(DeclaringTypeName)
|
|
||||||
.Append(".")
|
.Append(".")
|
||||||
.Append(Name);
|
.Append(Name);
|
||||||
}
|
}
|
||||||
@ -145,5 +142,10 @@ namespace System.Diagnostics
|
|||||||
|
|
||||||
return builder;
|
return builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private StringBuilder AppendDeclaringTypeName(StringBuilder builder)
|
||||||
|
{
|
||||||
|
return DeclaringType != null ? builder.AppendTypeDisplayName(DeclaringType, fullName: true, includeGenericParameterNames: true) : builder;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,8 +9,6 @@ namespace System.Diagnostics
|
|||||||
{
|
{
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
|
|
||||||
public string Type { get; set; }
|
|
||||||
|
|
||||||
public Type ResolvedType { get; set; }
|
public Type ResolvedType { get; set; }
|
||||||
|
|
||||||
public string Prefix { get; set; }
|
public string Prefix { get; set; }
|
||||||
@ -25,7 +23,15 @@ namespace System.Diagnostics
|
|||||||
.Append(" ");
|
.Append(" ");
|
||||||
}
|
}
|
||||||
|
|
||||||
sb.Append(Type);
|
if (ResolvedType != null)
|
||||||
|
{
|
||||||
|
AppendTypeName(sb);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sb.Append("?");
|
||||||
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(Name))
|
if (!string.IsNullOrEmpty(Name))
|
||||||
{
|
{
|
||||||
sb.Append(" ")
|
sb.Append(" ")
|
||||||
@ -34,5 +40,10 @@ namespace System.Diagnostics
|
|||||||
|
|
||||||
return sb;
|
return sb;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected virtual void AppendTypeName(StringBuilder sb)
|
||||||
|
{
|
||||||
|
sb.AppendTypeDisplayName(ResolvedType, fullName: false, includeGenericParameterNames: true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
49
src/Ben.Demystifier/StringBuilderExtentions.cs
Normal file
49
src/Ben.Demystifier/StringBuilderExtentions.cs
Normal file
@ -0,0 +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.Collections.Generic.Enumerable;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace System.Diagnostics
|
||||||
|
{
|
||||||
|
public static class StringBuilderExtentions
|
||||||
|
{
|
||||||
|
public static StringBuilder AppendDemystified(this StringBuilder builder, Exception exception)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var stackTrace = new EnhancedStackTrace(exception);
|
||||||
|
|
||||||
|
if (stackTrace.FrameCount > 0)
|
||||||
|
{
|
||||||
|
stackTrace.Append(builder);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void AppendInnerException(this StringBuilder builder, Exception exception)
|
||||||
|
=> builder.Append(" ---> ")
|
||||||
|
.AppendDemystified(exception)
|
||||||
|
.AppendLine()
|
||||||
|
.Append(" --- End of inner exception stack trace ---");
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -7,7 +7,7 @@ using System.Text;
|
|||||||
namespace System.Diagnostics
|
namespace System.Diagnostics
|
||||||
{
|
{
|
||||||
// Adapted from https://github.com/aspnet/Common/blob/dev/shared/Microsoft.Extensions.TypeNameHelper.Sources/TypeNameHelper.cs
|
// Adapted from https://github.com/aspnet/Common/blob/dev/shared/Microsoft.Extensions.TypeNameHelper.Sources/TypeNameHelper.cs
|
||||||
public class TypeNameHelper
|
public static class TypeNameHelper
|
||||||
{
|
{
|
||||||
public static readonly Dictionary<Type, string> BuiltInTypeNames = new Dictionary<Type, string>
|
public static readonly Dictionary<Type, string> BuiltInTypeNames = new Dictionary<Type, string>
|
||||||
{
|
{
|
||||||
@ -43,6 +43,12 @@ namespace System.Diagnostics
|
|||||||
return builder.ToString();
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns a name of given generic type without '`'.
|
/// Returns a name of given generic type without '`'.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
62
src/Ben.Demystifier/ValueTupleResolvedParameter.cs
Normal file
62
src/Ben.Demystifier/ValueTupleResolvedParameter.cs
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
// 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.Diagnostics.Internal;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace System.Diagnostics
|
||||||
|
{
|
||||||
|
public class ValueTupleResolvedParameter : ResolvedParameter
|
||||||
|
{
|
||||||
|
public IList<string> TupleNames { get; set; }
|
||||||
|
|
||||||
|
protected override void AppendTypeName(StringBuilder sb)
|
||||||
|
{
|
||||||
|
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(">");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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], fullName: false, includeGenericParameterNames: true);
|
||||||
|
|
||||||
|
if (i >= TupleNames.Count)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var argName = TupleNames[i];
|
||||||
|
if (argName == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
sb.Append(" ");
|
||||||
|
sb.Append(argName);
|
||||||
|
}
|
||||||
|
|
||||||
|
sb.Append(")");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user