You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

128 lines
4.0 KiB

  1. // Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
  2. //
  3. // Permission is hereby granted, free of charge, to any person obtaining a copy of this
  4. // software and associated documentation files (the "Software"), to deal in the Software
  5. // without restriction, including without limitation the rights to use, copy, modify, merge,
  6. // publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
  7. // to whom the Software is furnished to do so, subject to the following conditions:
  8. //
  9. // The above copyright notice and this permission notice shall be included in all copies or
  10. // substantial portions of the Software.
  11. //
  12. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
  13. // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
  14. // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
  15. // FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
  16. // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  17. // DEALINGS IN THE SOFTWARE.
  18. using System;
  19. using System.Collections.Generic;
  20. using System.Diagnostics;
  21. using System.Linq;
  22. using System.Threading;
  23. using ICSharpCode.ILSpy.Controls;
  24. namespace ICSharpCode.ILSpy
  25. {
  26. class ILSpyTraceListener : DefaultTraceListener
  27. {
  28. [Conditional("DEBUG")]
  29. public static void Install()
  30. {
  31. Trace.Listeners.Clear();
  32. Trace.Listeners.Add(new ILSpyTraceListener());
  33. }
  34. public ILSpyTraceListener()
  35. {
  36. base.AssertUiEnabled = false;
  37. }
  38. HashSet<string> ignoredStacks = new HashSet<string>();
  39. bool dialogIsOpen;
  40. public override void Fail(string message)
  41. {
  42. this.Fail(message, null);
  43. }
  44. public override void Fail(string message, string detailMessage)
  45. {
  46. base.Fail(message, detailMessage); // let base class write the assert to the debug console
  47. string topFrame = "";
  48. string stackTrace = "";
  49. try
  50. {
  51. stackTrace = new StackTrace(true).ToString();
  52. var frames = stackTrace.Split('\r', '\n')
  53. .Where(f => f.Length > 0)
  54. .SkipWhile(f => f.Contains("ILSpyTraceListener") || f.Contains("System.Diagnostics"))
  55. .ToList();
  56. topFrame = frames[0];
  57. stackTrace = string.Join(Environment.NewLine, frames);
  58. }
  59. catch { }
  60. lock (ignoredStacks)
  61. {
  62. if (ignoredStacks.Contains(topFrame))
  63. return;
  64. if (dialogIsOpen)
  65. return;
  66. dialogIsOpen = true;
  67. }
  68. // We might be unable to display a dialog here, e.g. because
  69. // we're on the UI thread but dispatcher processing is disabled.
  70. // In any case, we don't want to pump messages while the dialog is displaying,
  71. // so we create a separate UI thread for the dialog:
  72. int result = 0;
  73. var thread = new Thread(() => result = ShowAssertionDialog(message, detailMessage, stackTrace));
  74. thread.SetApartmentState(ApartmentState.STA);
  75. thread.Start();
  76. thread.Join();
  77. if (result == 0)
  78. { // throw
  79. throw new AssertionFailedException(message);
  80. }
  81. else if (result == 1)
  82. { // debug
  83. Debugger.Break();
  84. }
  85. else if (result == 2)
  86. { // ignore
  87. }
  88. else if (result == 3)
  89. {
  90. lock (ignoredStacks)
  91. {
  92. ignoredStacks.Add(topFrame);
  93. }
  94. }
  95. }
  96. int ShowAssertionDialog(string message, string detailMessage, string stackTrace)
  97. {
  98. message = message + Environment.NewLine + detailMessage + Environment.NewLine + stackTrace;
  99. string[] buttonTexts = { "Throw", "Debug", "Ignore", "Ignore All" };
  100. CustomDialog inputBox = new CustomDialog("Assertion Failed", message.TakeStartEllipsis(750), -1, 2, buttonTexts);
  101. inputBox.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
  102. inputBox.ShowInTaskbar = true; // make this window more visible, because it effectively interrupts the decompilation process.
  103. try
  104. {
  105. inputBox.ShowDialog();
  106. return inputBox.Result;
  107. }
  108. finally
  109. {
  110. dialogIsOpen = false;
  111. inputBox.Dispose();
  112. }
  113. }
  114. }
  115. class AssertionFailedException : Exception
  116. {
  117. public AssertionFailedException(string message) : base(message) { }
  118. }
  119. }