Created
June 27, 2012 13:15
-
-
Save anonymous/3003999 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Diagnostics; | |
using System.Reflection; | |
using System.Text; | |
using NDepend.Attributes; | |
using NDepend.Helpers; | |
namespace NDepend.Product.ErrorHandling { | |
#if DEBUG | |
[FullCovered] | |
#endif | |
internal static class StackTraceHelper { | |
internal static string FormatStackTrace(Exception ex) { | |
Debug.Assert(ex != null); | |
#if DEBUG | |
return FormatUnlocalizedStackTraceFromString(ex.StackTrace); | |
#else | |
return FormatUnlocalizedStackTraceWithILOffset(ex); | |
#endif | |
} | |
#region FormatUnlocalizedStackTraceWithILOffset() | |
// 27June2012: Idea to get the ILOffset from stackTrace: http://www.timstall.com/2008/07/getting-file-and-line-numbers-without.html | |
#if DEBUG | |
[IsNotDeadCode] // Coz used by tests and release version!!! | |
#endif | |
internal static string FormatUnlocalizedStackTraceWithILOffset(Exception ex) { | |
Debug.Assert(ex != null); | |
try { | |
//Get offset: | |
var stackTrace = new StackTrace(ex, true); | |
StackFrame[] stackFrames = stackTrace.GetFrames(); | |
var sb = new StringBuilder(); | |
var stackFramesLength = new int[stackFrames.Length]; | |
for (var i = 0; i < stackFramesLength.Length; i++) { | |
var stacfkFrame = stackFrames[i]; | |
var method = stacfkFrame.GetMethod(); | |
var parameters = GetMethodParameters(method); | |
var ilOffset = GetILOffset(stacfkFrame.GetILOffset()); | |
sb.Append(string.Format(" {0}.{1}({2}) {3} \r\n", | |
method.ReflectedType.FullName, | |
method.Name, | |
parameters, | |
ilOffset)); | |
} | |
return sb.ToString(); | |
} catch { | |
return FormatUnlocalizedStackTraceFromString(ex.StackTrace); | |
} | |
} | |
private static string GetILOffset(int ilOffset) { | |
Debug.Assert(ilOffset >= 0); | |
// Format to hexadecimal to have a Reflector like IL instruction OffSet | |
var ilOffsetHexString = ilOffset.ToString("X").ToLower(); | |
// Get a Reflector-like ILOffset like "L_018e" | |
var sb = new StringBuilder("L_"); | |
if(ilOffsetHexString.Length < 4) { | |
sb.Append(new string('0', 4 - ilOffsetHexString.Length)); | |
} | |
sb.Append(ilOffsetHexString); | |
return sb.ToString(); | |
} | |
private static string GetMethodParameters(MethodBase method) { | |
Debug.Assert(method != null); | |
var parameters = method.GetParameters(); | |
var length = parameters.Length; | |
var sb = new StringBuilder(); | |
for(var i=0; i< length; i++) { | |
var parameter = parameters[i]; | |
sb.Append(parameter.ParameterType.Name); | |
sb.Append(" "); | |
sb.Append(parameter.Name); | |
if(i < length -1) { | |
sb.Append(", "); | |
} | |
} | |
return sb.ToString(); | |
} | |
#endregion FormatUnlocalizedStackTraceWithILOffset() | |
#region FormatUnlocalizedStackTraceFromString() | |
internal const string EMPTY_STACK_TRACE = "Empty StackTrace"; | |
// | |
// OldVersion, still used in Debug mode to get the Line number | |
// and used in case FormatUnlocalizedStackTraceWithILOffset() has a problem! | |
// | |
#if DEBUG | |
[IsNotDeadCode] // Coz used by tests and release version!!! | |
#endif | |
// StackTrace lines are prefixed with " at " or " à " or " в " or " 場所 " that we need to remove | |
internal static string FormatUnlocalizedStackTraceFromString(string stackTraceIn) { | |
if(stackTraceIn.IsNullOrEmpty()) { | |
return EMPTY_STACK_TRACE; | |
} | |
var lines = stackTraceIn.Split(new char[] {'\r'}); | |
Debug.Assert(lines != null); | |
Debug.Assert(lines.Length >= 1); | |
var sb = new StringBuilder(); | |
for (var i = 0; i < lines.Length; i++ ) { | |
var unlocalizedLine = UnlocalizeLine(lines[i]); | |
if (i > 0) { sb.Append("\r\n"); } | |
sb.Append(unlocalizedLine); | |
} | |
return sb.ToString(); | |
} | |
private static object UnlocalizeLine(string lineIn) { | |
Debug.Assert(!lineIn.IsNullOrEmpty()); | |
lineIn = lineIn.Replace("\n", ""); // Eventually discard \n at the beginning | |
int indexFirstNonWhiteSpace = 0; | |
for (indexFirstNonWhiteSpace = 0; indexFirstNonWhiteSpace < lineIn.Length; indexFirstNonWhiteSpace++) { | |
if (lineIn[indexFirstNonWhiteSpace] != ' ') { break; } | |
} | |
// lineIn is like | |
// '\n' 'white' 'white' 'at' 'white' "xxxx | |
// The idea is to get rid of the localizable 'at' and to transform it in | |
// 'white' "xxxx | |
var indexOfSecondSpace = lineIn.IndexOf(' ', indexFirstNonWhiteSpace); | |
if (indexOfSecondSpace == -1) { return lineIn; } | |
var lineOut = lineIn.Substring(indexOfSecondSpace, lineIn.Length - indexOfSecondSpace); | |
return lineOut; | |
} | |
#endregion FormatUnlocalizedStackTraceFromString() | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment