DTLib.Demystifier/EnhancedStackTrace.cs
2024-09-20 02:23:38 +05:00

85 lines
2.9 KiB
C#

// 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 DTLib.Demystifier;
public partial class EnhancedStackTrace : StackTrace, IEnumerable<EnhancedStackFrame>
{
private readonly List<EnhancedStackFrame> _frames;
/// <summary>
/// Initializes a new instance of the System.Diagnostics.StackTrace class using the
/// provided exception object
/// </summary>
public EnhancedStackTrace(Exception e)
{
_frames = GetFrames(new StackTrace(e, true));
}
public EnhancedStackTrace(StackTrace stackTrace)
{
_frames = GetFrames(stackTrace);
}
/// <returns>The number of frames in the stack trace.</returns>
public override int FrameCount => _frames.Count;
IEnumerator<EnhancedStackFrame> IEnumerable<EnhancedStackFrame>.GetEnumerator() => _frames.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => _frames.GetEnumerator();
public static EnhancedStackTrace Current()
=> new EnhancedStackTrace(new StackTrace(1 /* skip this one frame */, true));
/// <param name="index">The index of the stack frame requested.</param>
/// <returns>The specified stack frame.</returns>
public override StackFrame GetFrame(int index) => _frames[index];
/// <returns>a copy of all stack frames in the current stack trace. </returns>
public override StackFrame[] GetFrames() => _frames.ToArray();
/// <summary>
/// Builds a readable representation of the stack trace.
/// </summary>
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 (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))
sb.Append(" in ").Append(TryGetFullPath(fileName!));
var lineNo = frame.GetFileLineNumber();
if (lineNo != 0)
sb.Append(':').Append(lineNo);
}
}
/// <summary>
/// Tries to convert a given <paramref name="filePath" /> to a full path.
/// Returns original value if the conversion isn't possible or a given path is relative.
/// </summary>
public static string TryGetFullPath(string filePath)
{
if (Uri.TryCreate(filePath, UriKind.Absolute, out var uri) && uri.IsFile)
return Uri.UnescapeDataString(uri.AbsolutePath);
if (Environment.OSVersion.Platform == PlatformID.Win32NT)
return filePath.Replace('/', '\\');
return filePath;
}
}