提交 ca3993b0 编写于 作者: J Jonathon Marolf 提交者: GitHub

Merge pull request #13026 from jmarolf/bugfix/get-callstack-on-codefix-crash

get callstack on codefix crash
......@@ -69,11 +69,11 @@ public override void HandleException(object provider, Exception exception)
{
base.HandleException(provider, exception);
_errorReportingService?.ShowErrorInfoForCodeFix(
codefixName: provider.GetType().Name,
OnEnable: () => { EnableProvider(provider); LogEnableProvider(provider); },
OnEnableAndIgnore: () => { EnableProvider(provider); IgnoreProvider(provider); LogEnableAndIgnoreProvider(provider); },
OnClose: () => LogLeaveDisabled(provider));
_errorReportingService?.ShowErrorInfo(String.Format(WorkspacesResources._0_encountered_an_error_and_has_been_disabled, provider.GetType().Name),
new ErrorReportingUI(WorkspacesResources.Show_Stack_Trace, ErrorReportingUI.UIKind.HyperLink, () => ShowDetailedErrorInfo(exception), closeAfterAction: false),
new ErrorReportingUI(WorkspacesResources.Enable, ErrorReportingUI.UIKind.Button, () => { EnableProvider(provider); LogEnableProvider(provider); }),
new ErrorReportingUI(WorkspacesResources.Enable_and_ignore_future_errors, ErrorReportingUI.UIKind.Button, () => { EnableProvider(provider); LogEnableProvider(provider); }),
new ErrorReportingUI(String.Empty, ErrorReportingUI.UIKind.Close, () => LogLeaveDisabled(provider)));
}
else
{
......@@ -93,6 +93,11 @@ public override void HandleException(object provider, Exception exception)
_errorLoggerService?.LogException(provider, exception);
}
private void ShowDetailedErrorInfo(Exception exception)
{
_errorReportingService.ShowDetailedErrorInfo(exception);
}
private static void LogLeaveDisabled(object provider)
{
LogAction(CodefixInfobar_LeaveDisabled, provider);
......
......@@ -8,9 +8,9 @@ namespace Microsoft.CodeAnalysis.Editor.Implementation.Workspaces
{
internal class EditorErrorReportingService : IErrorReportingService
{
public void ShowErrorInfoForCodeFix(string codefixName, Action OnEnable, Action OnEnableAndIgnore, Action OnClose)
public void ShowDetailedErrorInfo(Exception exception)
{
ShowErrorInfo($"{codefixName} crashed");
Logger.Log(FunctionId.Extension_Exception, exception.StackTrace);
}
public void ShowErrorInfo(string message, params ErrorReportingUI[] items)
......
<ui:DialogWindow x:Class="Microsoft.VisualStudio.LanguageServices.Implementation.DetailedErrorInfoDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:local="clr-namespace:Microsoft.VisualStudio.LanguageServices.Implementation"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:ui="clr-namespace:Microsoft.VisualStudio.PlatformUI;assembly=Microsoft.VisualStudio.Shell.14.0"
xmlns:vs="clr-namespace:Microsoft.VisualStudio.Shell;assembly=Microsoft.VisualStudio.Shell.14.0"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
mc:Ignorable="d"
x:ClassModifier="internal"
ShowInTaskbar="False"
WindowStartupLocation="CenterOwner"
Background="{DynamicResource {x:Static vs:VsBrushes.ToolboxBackgroundKey}}"
Foreground="{DynamicResource {x:Static vs:VsBrushes.ToolboxGradientKey}}"
d:DesignHeight="300" d:DesignWidth="300"
SizeToContent="Height"
MaxWidth="768"
MinWidth="300"
MinHeight="300">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="38"/>
</Grid.RowDefinitions>
<ScrollViewer Grid.Column="0" Grid.Row="0"
HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Auto"
Style="{DynamicResource {x:Static vs:VsResourceKeys.ScrollViewerStyleKey}}">
<TextBox
Name="stackTraceText"
IsReadOnly="True"
Style="{DynamicResource {x:Static vs:VsResourceKeys.TextBoxStyleKey}}"/>
</ScrollViewer>
<StackPanel Grid.Row="1" Grid.Column="0" Orientation="Horizontal" HorizontalAlignment="Right">
<Button Name="CopyButton"
Height="24"
Margin="0,0,10,0"
Click="CopyMessageToClipBoard"
Style="{DynamicResource {x:Static vs:VsResourceKeys.ButtonStyleKey}}"/>
<Button Name="CloseButton"
Height="24" Width="70"
Margin="0,0,10,0"
Click="CloseWindow"
Style="{DynamicResource {x:Static vs:VsResourceKeys.ButtonStyleKey}}"/>
</StackPanel>
</Grid>
</ui:DialogWindow>
\ No newline at end of file
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Forms;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Microsoft.VisualStudio.PlatformUI;
using Microsoft.VisualStudio.Shell;
namespace Microsoft.VisualStudio.LanguageServices.Implementation
{
internal partial class DetailedErrorInfoDialog : DialogWindow
{
private readonly string errorInfo;
internal DetailedErrorInfoDialog(string title, string errorInfo)
{
InitializeComponent();
this.errorInfo = errorInfo;
this.Title = title;
stackTraceText.AppendText(errorInfo);
this.CopyButton.Content = ServicesVSResources.Copy_to_clipboard;
this.CloseButton.Content = ServicesVSResources.Close;
}
private void CopyMessageToClipBoard(object sender, RoutedEventArgs e)
{
try
{
System.Windows.Clipboard.SetText(errorInfo);
}
catch (Exception)
{
// rdpclip.exe not running in a TS session, ignore
}
}
private void CloseWindow(object sender, RoutedEventArgs e)
{
this.Close();
}
}
}
using System;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
namespace Microsoft.VisualStudio.LanguageServices.Implementation
{
internal partial class VisualStudioErrorReportingService
{
private static string GetFormattedExceptionStack(Exception exception)
{
var aggregate = exception as AggregateException;
if (aggregate != null)
{
return GetStackForAggregateException(exception, aggregate);
}
return GetStackForException(exception, false);
}
private static string GetStackForAggregateException(Exception exception, AggregateException aggregate)
{
var text = GetStackForException(exception, true);
for (int i = 0; i < aggregate.InnerExceptions.Count; i++)
{
text = string.Format("{0}{1}---> (Inner Exception #{2}) {3}{4}{5}", text,
Environment.NewLine, i, GetFormattedExceptionStack(aggregate.InnerExceptions[i]), "<---", Environment.NewLine);
}
return text;
}
private static string GetStackForException(Exception exception, bool includeMessageOnly)
{
var message = exception.Message;
var className = exception.GetType().ToString();
var stackText = message.Length <= 0
? className
: className + " : " + message;
var innerException = exception.InnerException;
if (innerException != null)
{
if (includeMessageOnly)
{
do
{
stackText += " ---> " + innerException.Message;
innerException = innerException.InnerException;
} while (innerException != null);
}
else
{
stackText += " ---> " + GetFormattedExceptionStack(innerException) + Environment.NewLine +
" " + ServicesVSResources.End_of_inner_exception_stack;
}
}
return stackText + Environment.NewLine + GetAsyncStackTrace(exception);
}
private static string GetAsyncStackTrace(Exception exception)
{
var stackTrace = new StackTrace(exception);
var stackFrames = stackTrace.GetFrames();
if (stackFrames == null)
{
return string.Empty;
}
var firstFrame = true;
var stringBuilder = new StringBuilder();
foreach (var frame in stackFrames)
{
var method = frame.GetMethod();
var declaringType = method?.DeclaringType;
if (declaringType != null && typeof(INotifyCompletion).IsAssignableFrom(declaringType))
{
continue;
}
if (firstFrame)
{
firstFrame = false;
}
else
{
stringBuilder.Append(Environment.NewLine);
}
stringBuilder.AppendFormat(" at ");
var isAsync = FormatMethodName(stringBuilder, declaringType);
if (!isAsync)
{
stringBuilder.Append(method?.Name);
var methodInfo = method as MethodInfo;
if (methodInfo?.IsGenericMethod == true)
{
FormatGenericArguments(stringBuilder, methodInfo.GetGenericArguments());
}
}
else if (declaringType?.IsGenericType == true)
{
FormatGenericArguments(stringBuilder, declaringType.GetGenericArguments());
}
stringBuilder.Append("(");
if (isAsync)
{
stringBuilder.Append(ServicesVSResources.Unknown_parameters);
}
else
{
FormatParameters(stringBuilder, method);
}
stringBuilder.Append(")");
}
return stringBuilder.ToString();
}
private static bool FormatMethodName(StringBuilder stringBuilder, Type declaringType)
{
if (declaringType == null)
{
return false;
}
var isAsync = false;
var fullName = declaringType.FullName.Replace('+', '.');
if (typeof(IAsyncStateMachine).GetTypeInfo().IsAssignableFrom(declaringType))
{
isAsync = true;
stringBuilder.Append("async ");
var start = fullName.LastIndexOf('<');
var end = fullName.LastIndexOf('>');
if (start >= 0 && end >= 0)
{
stringBuilder.Append(fullName.Remove(start, 1).Substring(0, end - 1));
}
else
{
stringBuilder.Append(fullName);
}
}
else
{
stringBuilder.Append(fullName);
stringBuilder.Append(".");
}
return isAsync;
}
private static void FormatGenericArguments(StringBuilder stringBuilder, Type[] genericTypeArguments)
{
if (genericTypeArguments.Length <= 0)
{
return;
}
stringBuilder.Append("[" + String.Join(",", genericTypeArguments.Select(args => args.Name)) + "]");
}
private static void FormatParameters(StringBuilder stringBuilder, MethodBase method) =>
stringBuilder.Append(string.Join(",", method?.GetParameters().Select(t => (t.ParameterType?.Name ?? "<UnknownType>") + " " + t.Name) ?? Array.Empty<string>()));
}
}
......@@ -14,7 +14,7 @@
namespace Microsoft.VisualStudio.LanguageServices.Implementation
{
internal class VisualStudioErrorReportingService : IErrorReportingService
internal partial class VisualStudioErrorReportingService : IErrorReportingService
{
private readonly static InfoBarButton s_enableItem = new InfoBarButton(ServicesVSResources.Enable);
private readonly static InfoBarButton s_enableAndIgnoreItem = new InfoBarButton(ServicesVSResources.Enable_and_ignore_future_errors);
......@@ -31,20 +31,6 @@ internal class VisualStudioErrorReportingService : IErrorReportingService
_listener = listener;
}
public void ShowErrorInfoForCodeFix(string codefixName, Action OnEnable, Action OnEnableAndIgnore, Action OnClose)
{
// We can be called from any thread since errors can occur anywhere, however we can only construct and InfoBar from the UI thread.
_foregroundNotificationService.RegisterNotification(() =>
{
IVsWindowFrame frame;
IVsInfoBarUIFactory factory;
if (_workspace.TryGetInfoBarData(out frame, out factory))
{
CreateInfoBarForCodeFix(factory, frame, string.Format(ServicesVSResources._0_encountered_an_error_and_has_been_disabled, codefixName), OnClose, OnEnable, OnEnableAndIgnore);
}
}, _listener.BeginAsyncOperation("Show InfoBar"));
}
public void ShowErrorInfo(string message, params ErrorReportingUI[] items)
{
// We can be called from any thread since errors can occur anywhere, however we can only construct and InfoBar from the UI thread.
......@@ -161,102 +147,16 @@ public void OnClosed(IVsInfoBarUIElement infoBarUIElement)
}
}
private void CreateInfoBarForCodeFix(IVsInfoBarUIFactory factory, IVsWindowFrame frame, string message, Action onClose, Action onEnable = null, Action onEnableAndIgnore = null)
{
object unknown;
if (ErrorHandler.Failed(frame.GetProperty((int)__VSFPROPID7.VSFPROPID_InfoBarHost, out unknown)))
{
return;
}
var textSpans = new List<IVsInfoBarTextSpan>()
{
new InfoBarTextSpan(message)
};
// create action item list
var actionItems = new List<IVsInfoBarActionItem>();
if (onEnable != null)
{
actionItems.Add(s_enableItem);
}
if (onEnableAndIgnore != null)
{
actionItems.Add(s_enableAndIgnoreItem);
}
var infoBarModel = new InfoBarModel(
textSpans,
actionItems.ToArray(),
KnownMonikers.StatusInformation,
isCloseButtonVisible: true);
IVsInfoBarUIElement infoBarUI;
if (!TryCreateInfoBarUI(factory, infoBarModel, out infoBarUI))
{
return;
}
uint? infoBarCookie = null;
var eventSink = new CodeFixInfoBarEvents(() =>
{
onClose();
if (infoBarCookie.HasValue)
{
infoBarUI.Unadvise(infoBarCookie.Value);
}
}, onEnable, onEnableAndIgnore);
uint cookie;
infoBarUI.Advise(eventSink, out cookie);
infoBarCookie = cookie;
IVsInfoBarHost host = (IVsInfoBarHost)unknown;
host.AddInfoBar(infoBarUI);
}
private class CodeFixInfoBarEvents : IVsInfoBarUIEvents
{
private readonly Action _onClose;
private readonly Action _onEnable;
private readonly Action _onEnableAndIgnore;
public CodeFixInfoBarEvents(Action onClose, Action onEnable = null, Action onEnableAndIgnore = null)
{
Contract.ThrowIfNull(onClose);
_onClose = onClose;
_onEnable = onEnable;
_onEnableAndIgnore = onEnableAndIgnore;
}
public void OnActionItemClicked(IVsInfoBarUIElement infoBarUIElement, IVsInfoBarActionItem actionItem)
{
if (actionItem.Equals(s_enableItem))
{
_onEnable?.Invoke();
}
if (actionItem.Equals(s_enableAndIgnoreItem))
{
_onEnableAndIgnore?.Invoke();
}
infoBarUIElement.Close();
}
public void OnClosed(IVsInfoBarUIElement infoBarUIElement)
{
_onClose();
}
}
private static bool TryCreateInfoBarUI(IVsInfoBarUIFactory infoBarUIFactory, IVsInfoBar infoBar, out IVsInfoBarUIElement uiElement)
{
uiElement = infoBarUIFactory.CreateInfoBar(infoBar);
return uiElement != null;
}
public void ShowDetailedErrorInfo(Exception exception)
{
string errorInfo = GetFormattedExceptionStack(exception);
(new DetailedErrorInfoDialog(exception.Message, errorInfo)).ShowModal();
}
}
}
......@@ -343,6 +343,15 @@ internal class ServicesVSResources {
}
}
/// <summary>
/// Looks up a localized string similar to Close.
/// </summary>
internal static string Close {
get {
return ResourceManager.GetString("Close", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Computing remove suppressions fix....
/// </summary>
......@@ -361,6 +370,15 @@ internal class ServicesVSResources {
}
}
/// <summary>
/// Looks up a localized string similar to Copy to Clipboard.
/// </summary>
internal static string Copy_to_clipboard {
get {
return ResourceManager.GetString("Copy_to_clipboard", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Could not find location of folder on disk.
/// </summary>
......@@ -523,6 +541,15 @@ internal class ServicesVSResources {
}
}
/// <summary>
/// Looks up a localized string similar to --- End of inner exception stack trace ---.
/// </summary>
internal static string End_of_inner_exception_stack {
get {
return ResourceManager.GetString("End_of_inner_exception_stack", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to End position must be &gt;= start position.
/// </summary>
......@@ -786,6 +813,15 @@ internal class ServicesVSResources {
}
}
/// <summary>
/// Looks up a localized string similar to in {0}:line {1}.
/// </summary>
internal static string in_0_line_1 {
get {
return ResourceManager.GetString("in_0_line_1", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Inherited By.
/// </summary>
......@@ -1689,6 +1725,15 @@ internal class ServicesVSResources {
}
}
/// <summary>
/// Looks up a localized string similar to &lt;Unknown Parameters&gt;.
/// </summary>
internal static string Unknown_parameters {
get {
return ResourceManager.GetString("Unknown_parameters", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Unknown rename type.
/// </summary>
......
......@@ -699,4 +699,19 @@ Additional information: {1}</value>
<data name="Prefer_predefined_type" xml:space="preserve">
<value>Prefer predefined type</value>
</data>
<data name="Copy_to_clipboard" xml:space="preserve">
<value>Copy to Clipboard</value>
</data>
<data name="Close" xml:space="preserve">
<value>Close</value>
</data>
<data name="End_of_inner_exception_stack" xml:space="preserve">
<value>--- End of inner exception stack trace ---</value>
</data>
<data name="in_0_line_1" xml:space="preserve">
<value>in {0}:line {1}</value>
</data>
<data name="Unknown_parameters" xml:space="preserve">
<value>&lt;Unknown Parameters&gt;</value>
</data>
</root>
\ No newline at end of file
......@@ -158,9 +158,13 @@
<Compile Include="Implementation\Watson\Watson.cs" />
<Compile Include="Implementation\Watson\WatsonErrorReport.cs" />
<Compile Include="Implementation\Watson\WatsonReporter.cs" />
<Compile Include="Implementation\Workspace\DetailedErrorInfoDialog.xaml.cs">
<DependentUpon>DetailedErrorInfoDialog.xaml</DependentUpon>
</Compile>
<Compile Include="Implementation\Workspace\Esent\EsentStorage.ProjectDocumentTableAccessor.cs" />
<Compile Include="Implementation\Workspace\Esent\EsentLogger.cs" />
<Compile Include="Implementation\Workspace\Esent\EsentStorage.ProjectDocumentTable.cs" />
<Compile Include="Implementation\Workspace\VisualStudioErrorReportingService.ExceptionFormatting.cs" />
<Compile Include="Implementation\Workspace\VisualStudioErrorReportingServiceFactory.cs" />
<Compile Include="Implementation\Workspace\VisualStudioErrorReportingService.cs" />
<Compile Include="Implementation\Workspace\VisualStudioNavigationOptions.cs" />
......@@ -712,6 +716,10 @@
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Implementation\Workspace\DetailedErrorInfoDialog.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="ServicesVSResources.resx">
......@@ -733,7 +741,6 @@
<Compile Include="SymbolSearch\SymbolSearchService.PatchService.cs" />
<None Include="project.json" />
<PublicAPI Include="PublicAPI.Shipped.txt" />
<PublicAPI Include="PublicAPI.Unshipped.txt" />
</ItemGroup>
<ItemGroup>
<VSCTCompile Include="Commands.vsct">
......
......@@ -8,8 +8,8 @@ namespace Microsoft.CodeAnalysis.Extensions
{
internal interface IErrorReportingService : IWorkspaceService
{
void ShowErrorInfoForCodeFix(string codefixName, Action OnEnable, Action OnEnableAndIgnore, Action OnClose);
void ShowErrorInfo(string message, params ErrorReportingUI[] items);
void ShowDetailedErrorInfo(Exception exception);
}
internal struct ErrorReportingUI
......
......@@ -61,6 +61,15 @@ internal class WorkspacesResources {
}
}
/// <summary>
/// Looks up a localized string similar to &apos;{0}&apos; encountered an error and has been disabled..
/// </summary>
internal static string _0_encountered_an_error_and_has_been_disabled {
get {
return ResourceManager.GetString("_0_encountered_an_error_and_has_been_disabled", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to &apos;{0}&apos; is already part of the workspace..
/// </summary>
......@@ -530,6 +539,24 @@ internal class WorkspacesResources {
}
}
/// <summary>
/// Looks up a localized string similar to Enable.
/// </summary>
internal static string Enable {
get {
return ResourceManager.GetString("Enable", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Enable and ignore future errors.
/// </summary>
internal static string Enable_and_ignore_future_errors {
get {
return ResourceManager.GetString("Enable_and_ignore_future_errors", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Exceptions:.
/// </summary>
......@@ -891,6 +918,15 @@ internal class WorkspacesResources {
}
}
/// <summary>
/// Looks up a localized string similar to Show Stack Trace.
/// </summary>
internal static string Show_Stack_Trace {
get {
return ResourceManager.GetString("Show_Stack_Trace", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Solution file not found: &apos;{0}&apos;.
/// </summary>
......
......@@ -474,4 +474,16 @@
<data name="Options_did_not_come_from_Workspace" xml:space="preserve">
<value>Options did not come from Workspace</value>
</data>
<data name="Enable" xml:space="preserve">
<value>Enable</value>
</data>
<data name="Enable_and_ignore_future_errors" xml:space="preserve">
<value>Enable and ignore future errors</value>
</data>
<data name="_0_encountered_an_error_and_has_been_disabled" xml:space="preserve">
<value>'{0}' encountered an error and has been disabled.</value>
</data>
<data name="Show_Stack_Trace" xml:space="preserve">
<value>Show Stack Trace</value>
</data>
</root>
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册