From 1b2da043a88a355e59587785fa84d4f94b991a87 Mon Sep 17 00:00:00 2001 From: Andrew Hall Date: Wed, 12 Jan 2022 17:02:16 -0800 Subject: [PATCH] Fix so that the stack trace explorer only automatically activates on focus if the clipboard has "at" trivia in the frame. --- .../StackTraceExplorer/IgnoredFrame.cs | 2 -- .../StackTraceExplorer/ParsedFrame.cs | 2 -- .../StackTraceExplorer/ParsedStackFrame.cs | 2 -- .../StackTraceExplorerCommandHandler.cs | 2 ++ .../StackTraceExplorerToolWindow.cs | 32 ++++++++++++++++++- .../Compiler/Core/Log/FunctionId.cs | 2 ++ 6 files changed, 35 insertions(+), 7 deletions(-) diff --git a/src/Features/Core/Portable/StackTraceExplorer/IgnoredFrame.cs b/src/Features/Core/Portable/StackTraceExplorer/IgnoredFrame.cs index 2ec8d7ad929cd..246a4443bba9e 100644 --- a/src/Features/Core/Portable/StackTraceExplorer/IgnoredFrame.cs +++ b/src/Features/Core/Portable/StackTraceExplorer/IgnoredFrame.cs @@ -13,8 +13,6 @@ public IgnoredFrame(string originalText) _originalText = originalText; } - public override bool IsStackFrame => false; - public override string ToString() { return _originalText; diff --git a/src/Features/Core/Portable/StackTraceExplorer/ParsedFrame.cs b/src/Features/Core/Portable/StackTraceExplorer/ParsedFrame.cs index 9d6ee17438a04..9e65a78a3290b 100644 --- a/src/Features/Core/Portable/StackTraceExplorer/ParsedFrame.cs +++ b/src/Features/Core/Portable/StackTraceExplorer/ParsedFrame.cs @@ -9,7 +9,5 @@ internal abstract class ParsedFrame public ParsedFrame() { } - - public abstract bool IsStackFrame { get; } } } diff --git a/src/Features/Core/Portable/StackTraceExplorer/ParsedStackFrame.cs b/src/Features/Core/Portable/StackTraceExplorer/ParsedStackFrame.cs index 4d971c5792925..5b464fc65d575 100644 --- a/src/Features/Core/Portable/StackTraceExplorer/ParsedStackFrame.cs +++ b/src/Features/Core/Portable/StackTraceExplorer/ParsedStackFrame.cs @@ -32,8 +32,6 @@ public ParsedStackFrame( public StackFrameCompilationUnit Root => Tree.Root; - public override bool IsStackFrame => true; - public override string ToString() { return Tree.Text.CreateString(); diff --git a/src/VisualStudio/Core/Def/StackTraceExplorer/StackTraceExplorerCommandHandler.cs b/src/VisualStudio/Core/Def/StackTraceExplorer/StackTraceExplorerCommandHandler.cs index 414b2775983b8..b077db9185a0a 100644 --- a/src/VisualStudio/Core/Def/StackTraceExplorer/StackTraceExplorerCommandHandler.cs +++ b/src/VisualStudio/Core/Def/StackTraceExplorer/StackTraceExplorerCommandHandler.cs @@ -6,6 +6,7 @@ using System.ComponentModel.Design; using System.IO.Packaging; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; +using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.StackTraceExplorer; using Microsoft.VisualStudio.LanguageServices.Setup; @@ -63,6 +64,7 @@ public int OnBroadcastMessage(uint msg, IntPtr wParam, IntPtr lParam) await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(); var windowFrame = (IVsWindowFrame)window.Frame; ErrorHandler.ThrowOnFailure(windowFrame.Show()); + Logger.Log(FunctionId.StackTraceToolWindow_ShowOnActivated, logLevel: LogLevel.Information); } }); diff --git a/src/VisualStudio/Core/Def/StackTraceExplorer/StackTraceExplorerToolWindow.cs b/src/VisualStudio/Core/Def/StackTraceExplorer/StackTraceExplorerToolWindow.cs index 8edc39cd79434..85c5a6cf01673 100644 --- a/src/VisualStudio/Core/Def/StackTraceExplorer/StackTraceExplorerToolWindow.cs +++ b/src/VisualStudio/Core/Def/StackTraceExplorer/StackTraceExplorerToolWindow.cs @@ -12,6 +12,7 @@ using System.Windows.Controls; using System.Windows.Input; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; +using Microsoft.CodeAnalysis.EmbeddedLanguages.StackFrame; using Microsoft.CodeAnalysis.StackTraceExplorer; using Microsoft.VisualStudio.Imaging; using Microsoft.VisualStudio.LanguageServices.Setup; @@ -72,7 +73,7 @@ public async Task ShouldShowOnActivatedAsync(CancellationToken cancellatio } var result = await StackTraceAnalyzer.AnalyzeAsync(text, cancellationToken).ConfigureAwait(false); - if (result.ParsedFrames.Any(static frame => frame.IsStackFrame)) + if (result.ParsedFrames.Any(static frame => FrameTriggersActivate(frame))) { await Root.ViewModel.AddNewTabAsync(result, text, cancellationToken).ConfigureAwait(false); return true; @@ -81,6 +82,35 @@ public async Task ShouldShowOnActivatedAsync(CancellationToken cancellatio return false; } + private static bool FrameTriggersActivate(ParsedFrame frame) + { + if (frame is not ParsedStackFrame parsedFrame) + { + return false; + } + + var methodDeclaration = parsedFrame.Root.MethodDeclaration; + + // Find the first token + var firstNodeOrToken = methodDeclaration.ChildAt(0); + while (firstNodeOrToken.IsNode) + { + firstNodeOrToken = firstNodeOrToken.Node.ChildAt(0); + } + + if (firstNodeOrToken.Token.LeadingTrivia.IsDefault) + { + return false; + } + + // If the stack frame starts with "at" we consider it a well formed stack frame and + // want to automatically open the window. This helps avoids some false positive cases + // where the window shows on code that parses as a stack frame but may not be. The explorer + // should still handle those cases if explicitly pasted in, but can lead to false positives + // when automatically opening. + return firstNodeOrToken.Token.LeadingTrivia.Any(t => t.Kind == StackFrameKind.AtTrivia); + } + public void InitializeIfNeeded(RoslynPackage roslynPackage) { if (_initialized) diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Log/FunctionId.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Log/FunctionId.cs index 103dd5f50ea7e..20787130a313c 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Log/FunctionId.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Log/FunctionId.cs @@ -537,5 +537,7 @@ internal enum FunctionId Inline_Hints_DoubleClick = 530, NavigateToExternalSources = 531, + + StackTraceToolWindow_ShowOnActivated = 540, } }