提交 3b370e7a 编写于 作者: D David Poeschl

Merge pull request #1697 from dpoeschl/RenameDuringDebugging

Commit rename on save and debugging run mode
......@@ -407,6 +407,7 @@
<Compile Include="Implementation\InlineRename\CommandHandlers\RenameCommandHandler_RenameHandler.cs" />
<Compile Include="Implementation\InlineRename\CommandHandlers\RenameCommandHandler_ReturnHandler.cs" />
<Compile Include="Implementation\InlineRename\CommandHandlers\RenameCommandHandler_SelectAllHandler.cs" />
<Compile Include="Implementation\InlineRename\CommandHandlers\RenameCommandHandler_SaveHandler.cs" />
<Compile Include="Implementation\InlineRename\CommandHandlers\RenameCommandHandler_TabHandler.cs" />
<Compile Include="Implementation\InlineRename\CommandHandlers\RenameCommandHandler_OpenLineAboveHandler.cs" />
<Compile Include="Implementation\InlineRename\CommandHandlers\RenameCommandHandler_TypeCharHandler.cs" />
......
......@@ -7,11 +7,14 @@
using Microsoft.CodeAnalysis.Editor.Shared.Extensions;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Operations;
using Microsoft.VisualStudio.Utilities;
namespace Microsoft.CodeAnalysis.Editor.Implementation.InlineRename
{
[ExportCommandHandler(PredefinedCommandHandlerNames.Rename,
ContentTypeNames.RoslynContentType)]
// Line commit and rename are both executed on Save. Ensure any rename session is committed
// before line commit runs to ensure changes from both are correctly applied.
[Order(Before = PredefinedCommandHandlerNames.Commit)]
[ExportCommandHandler(PredefinedCommandHandlerNames.Rename, ContentTypeNames.RoslynContentType)]
internal partial class RenameCommandHandler
{
private readonly InlineRenameService _renameService;
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.CodeAnalysis.Editor.Commands;
using Microsoft.VisualStudio.Text.Editor;
namespace Microsoft.CodeAnalysis.Editor.Implementation.InlineRename
{
internal partial class RenameCommandHandler : ICommandHandler<SaveCommandArgs>
{
public CommandState GetCommandState(SaveCommandArgs args, Func<CommandState> nextHandler)
{
return GetCommandState(nextHandler);
}
public void ExecuteCommand(SaveCommandArgs args, Action nextHandler)
{
if (_renameService.ActiveSession != null)
{
_renameService.ActiveSession.Commit();
((IWpfTextView)args.TextView).VisualElement.Focus();
}
nextHandler();
}
}
}
......@@ -6,6 +6,7 @@
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Threading;
using Microsoft.CodeAnalysis.EditAndContinue;
using Microsoft.CodeAnalysis.Editor.Host;
using Microsoft.CodeAnalysis.Editor.Shared.Extensions;
using Microsoft.CodeAnalysis.Editor.Shared.SuggestionSupport;
......@@ -31,6 +32,7 @@ internal partial class InlineRenameSession : ForegroundThreadAffinitizedObject,
private readonly ITextBufferAssociatedViewService _textBufferAssociatedViewService;
private readonly ITextBufferFactoryService _textBufferFactoryService;
private readonly IEnumerable<IRefactorNotifyService> _refactorNotifyServices;
private readonly IEditAndContinueWorkspaceService _editAndContinueWorkspaceService;
private readonly IAsynchronousOperationListener _asyncListener;
private readonly Solution _baseSolution;
private readonly Document _triggerDocument;
......@@ -118,9 +120,20 @@ internal partial class InlineRenameSession : ForegroundThreadAffinitizedObject,
_baseSolution = _triggerDocument.Project.Solution;
this.UndoManager = workspace.Services.GetService<IInlineRenameUndoManager>();
this._editAndContinueWorkspaceService = workspace.Services.GetService<IEditAndContinueWorkspaceService>();
this._editAndContinueWorkspaceService.BeforeDebuggingStateChanged += OnBeforeDebuggingStateChanged;
InitializeOpenBuffers(triggerSpan);
}
private void OnBeforeDebuggingStateChanged(object sender, DebuggingStateChangedEventArgs args)
{
if (args.After == DebuggingState.Run)
{
Commit();
}
}
public string OriginalSymbolName
{
get
......@@ -520,8 +533,8 @@ public void Commit(bool previewChanges = false)
private void EndRenameSession()
{
_editAndContinueWorkspaceService.BeforeDebuggingStateChanged -= OnBeforeDebuggingStateChanged;
CancelAllOpenDocumentTrackingTasks();
RenameTrackingDismisser.DismissRenameTracking(_workspace, _workspace.GetOpenDocumentIds());
_inlineRenameSessionDurationLogBlock.Dispose();
}
......@@ -571,8 +584,7 @@ private void CommitCore(IWaitContext waitContext, bool previewChanges)
LogRenameSession(RenameLogMessage.UserActionOutcome.Committed, previewChanges);
RenameTrackingDismisser.DismissRenameTracking(_workspace, _workspace.GetOpenDocumentIds());
_inlineRenameSessionDurationLogBlock.Dispose();
EndRenameSession();
}
}
......
......@@ -4,9 +4,9 @@ Imports System.Threading
Imports Microsoft.CodeAnalysis.CodeActions
Imports Microsoft.CodeAnalysis.CodeRefactorings
Imports Microsoft.CodeAnalysis.CSharp.CodeRefactorings.IntroduceVariable
Imports Microsoft.CodeAnalysis.EditAndContinue
Imports Microsoft.CodeAnalysis.Editor.Host
Imports Microsoft.CodeAnalysis.Editor.UnitTests.RenameTracking
Imports Microsoft.CodeAnalysis.Editor.UnitTests.Utilities
Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces
Imports Microsoft.CodeAnalysis.Notification
Imports Microsoft.CodeAnalysis.Options
......@@ -1225,5 +1225,87 @@ class C
VerifyRenameOptionChangedSessionCommit(workspace, "M", "Sa", renameOverloads:=True)
End Using
End Sub
<Fact>
<Trait(Traits.Feature, Traits.Features.Rename)>
<WorkItem(1142095)>
Public Sub RenameCommitsWhenDebuggingStarts()
Using workspace = CreateWorkspaceWithWaiter(
<Workspace>
<Project Language="C#" CommonReferences="true">
<Document>
class [|$$Foo|]
{
void Blah()
{
[|Foo|] f = new [|Foo|]();
}
}
</Document>
</Project>
</Workspace>)
Dim session = StartSession(workspace)
' Type a bit in the file
Dim caretPosition = workspace.Documents.Single(Function(d) d.CursorPosition.HasValue).CursorPosition.Value
Dim textBuffer = workspace.Documents.Single().TextBuffer
textBuffer.Insert(caretPosition, "Bar")
' Make sure the RenameService's ActiveSession is still there
Dim renameService = workspace.GetService(Of IInlineRenameService)()
Assert.NotNull(renameService.ActiveSession)
' Simulate starting a debugging session
Dim editAndContinueWorkspaceService = workspace.Services.GetService(Of IEditAndContinueWorkspaceService)
editAndContinueWorkspaceService.OnBeforeDebuggingStateChanged(DebuggingState.Design, DebuggingState.Run)
' Ensure the rename was committed
Assert.Null(renameService.ActiveSession)
VerifyTagsAreCorrect(workspace, "BarFoo")
End Using
End Sub
<Fact>
<Trait(Traits.Feature, Traits.Features.Rename)>
<WorkItem(1142095)>
Public Sub RenameCommitsWhenExitingDebuggingBreakMode()
Using workspace = CreateWorkspaceWithWaiter(
<Workspace>
<Project Language="C#" CommonReferences="true">
<Document>
class [|$$Foo|]
{
void Blah()
{
[|Foo|] f = new [|Foo|]();
}
}
</Document>
</Project>
</Workspace>)
Dim session = StartSession(workspace)
' Type a bit in the file
Dim caretPosition = workspace.Documents.Single(Function(d) d.CursorPosition.HasValue).CursorPosition.Value
Dim textBuffer = workspace.Documents.Single().TextBuffer
textBuffer.Insert(caretPosition, "Bar")
' Make sure the RenameService's ActiveSession is still there
Dim renameService = workspace.GetService(Of IInlineRenameService)()
Assert.NotNull(renameService.ActiveSession)
' Simulate ending break mode in the debugger (by stepping or continuing)
Dim editAndContinueWorkspaceService = workspace.Services.GetService(Of IEditAndContinueWorkspaceService)
editAndContinueWorkspaceService.OnBeforeDebuggingStateChanged(DebuggingState.Break, DebuggingState.Run)
' Ensure the rename was committed
Assert.Null(renameService.ActiveSession)
VerifyTagsAreCorrect(workspace, "BarFoo")
End Using
End Sub
End Class
End Namespace
End Namespace
\ No newline at end of file
......@@ -992,5 +992,46 @@ partial class [|Program|]
Assert.Equal(String.Empty, view.Caret.Position.BufferPosition.GetContainingLine.GetText())
End Using
End Sub
<Fact>
<WorkItem(1142095)>
<Trait(Traits.Feature, Traits.Features.Rename)>
Public Sub SaveDuringRenameCommits()
Using workspace = CreateWorkspaceWithWaiter(
<Workspace>
<Project Language="C#" CommonReferences="true">
<Document>
class [|$$Foo|]
{
[|Foo|] f;
}
</Document>
</Project>
</Workspace>)
Dim view = workspace.Documents.Single().GetTextView()
Dim commandHandler As New RenameCommandHandler(workspace.GetService(Of InlineRenameService),
workspace.GetService(Of IEditorOperationsFactoryService),
workspace.GetService(Of IWaitIndicator))
Dim session = StartSession(workspace)
WaitForRename(workspace)
Dim editorOperations = workspace.GetService(Of IEditorOperationsFactoryService).GetEditorOperations(view)
' Type first in the main identifier
view.Selection.Clear()
view.Caret.MoveTo(New SnapshotPoint(view.TextBuffer.CurrentSnapshot, workspace.Documents.Single(Function(d) d.CursorPosition.HasValue).CursorPosition.Value))
commandHandler.ExecuteCommand(New TypeCharCommandArgs(view, view.TextBuffer, "B"c), Sub() editorOperations.InsertText("B"))
' Now save the document, which should commit Rename
commandHandler.ExecuteCommand(New SaveCommandArgs(view, view.TextBuffer), Sub() Exit Sub)
VerifyTagsAreCorrect(workspace, "BFoo")
' Rename session was indeed commited and is no longer active
Assert.Null(workspace.GetService(Of IInlineRenameService).ActiveSession)
End Using
End Sub
End Class
End Namespace
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
namespace Microsoft.CodeAnalysis.EditAndContinue
{
internal enum DebuggingState
{
Design,
Run,
Break
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Diagnostics;
namespace Microsoft.CodeAnalysis.EditAndContinue
{
internal sealed class DebuggingStateChangedEventArgs
{
public DebuggingState Before { get; }
public DebuggingState After { get; }
public DebuggingStateChangedEventArgs(DebuggingState before, DebuggingState after)
{
Debug.Assert(before != after);
this.Before = before;
this.After = after;
}
}
}
......@@ -15,6 +15,8 @@ internal sealed class EditAndContinueWorkspaceService : IEditAndContinueWorkspac
private DebuggingSession _debuggingSession;
private EditSession _editSession;
public event EventHandler<DebuggingStateChangedEventArgs> BeforeDebuggingStateChanged;
internal EditAndContinueWorkspaceService(IDiagnosticAnalyzerService diagnosticService)
{
Debug.Assert(diagnosticService != null);
......@@ -37,6 +39,11 @@ public EditSession EditSession
}
}
public void OnBeforeDebuggingStateChanged(DebuggingState before, DebuggingState after)
{
BeforeDebuggingStateChanged?.Invoke(this, new DebuggingStateChangedEventArgs(before, after));
}
public void StartDebuggingSession(Solution currentSolution)
{
Debug.Assert(_debuggingSession == null && _editSession == null);
......
......@@ -12,6 +12,9 @@ internal interface IEditAndContinueWorkspaceService : IWorkspaceService
EditSession EditSession { get; }
DebuggingSession DebuggingSession { get; }
event EventHandler<DebuggingStateChangedEventArgs> BeforeDebuggingStateChanged;
void OnBeforeDebuggingStateChanged(DebuggingState before, DebuggingState after);
void StartDebuggingSession(Solution currentSolution);
void StartEditSession(
......
......@@ -219,6 +219,8 @@
<Compile Include="Diagnostics\PredefinedDiagnosticProviderNames.cs" />
<Compile Include="Diagnostics\UpdateArgsId.cs" />
<Compile Include="Diagnostics\WorkspaceAnalyzerOptions.cs" />
<Compile Include="EditAndContinue\DebuggingState.cs" />
<Compile Include="EditAndContinue\DebuggingStateChangedEventArgs.cs" />
<Compile Include="EditAndContinue\EncDebuggingSessionInfo.cs" />
<Compile Include="EditAndContinue\EncEditSessionInfo.cs" />
<Compile Include="EditAndContinue\BidirectionalMap.cs" />
......
......@@ -220,6 +220,8 @@ public int StartDebuggingPE()
Debug.Assert(s_breakStateProjectCount == 0);
Debug.Assert(s_breakStateEnteredProjects.Count == 0);
_encService.OnBeforeDebuggingStateChanged(DebuggingState.Design, DebuggingState.Run);
_encService.StartDebuggingSession(_vsProject.VisualStudioWorkspace.CurrentSolution);
s_encDebuggingSessionInfo = new EncDebuggingSessionInfo();
......@@ -297,6 +299,8 @@ public int StopDebuggingPE()
// Avoid ending the debug session if it has already been ended.
if (_encService.DebuggingSession != null)
{
_encService.OnBeforeDebuggingStateChanged(DebuggingState.Run, DebuggingState.Design);
_encService.EndDebuggingSession();
LogEncSession();
......@@ -424,6 +428,7 @@ public int EnterBreakStateOnPE(Interop.ENC_BREAKSTATE_REASON encBreakReason, She
using (NonReentrantContext)
{
log.Write("Enter {2}Break Mode: project '{0}', AS#: {1}", _vsProject.DisplayName, pActiveStatements != null ? pActiveStatements.Length : -1, encBreakReason == Interop.ENC_BREAKSTATE_REASON.ENC_BREAK_EXCEPTION ? "Exception " : "");
Debug.Assert(cActiveStatements == (pActiveStatements != null ? pActiveStatements.Length : 0));
Debug.Assert(s_breakStateProjectCount < s_debugStateProjectCount);
Debug.Assert(s_breakStateProjectCount > 0 || _exceptionRegions.Count == 0);
......@@ -432,6 +437,8 @@ public int EnterBreakStateOnPE(Interop.ENC_BREAKSTATE_REASON encBreakReason, She
if (s_breakStateEntrySolution == null)
{
_encService.OnBeforeDebuggingStateChanged(DebuggingState.Run, DebuggingState.Break);
s_breakStateEntrySolution = _vsProject.VisualStudioWorkspace.CurrentSolution;
}
......@@ -868,6 +875,8 @@ public int ExitBreakStateOnPE()
{
Debug.Assert(s_breakStateProjectCount == s_debugStateProjectCount);
_encService.OnBeforeDebuggingStateChanged(DebuggingState.Break, DebuggingState.Run);
_encService.EditSession.LogEditSession(s_encDebuggingSessionInfo);
_encService.EndEditSession();
_trackingService.EndTracking();
......
......@@ -13,7 +13,6 @@
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Notification;
using Microsoft.VisualStudio.ComponentModelHost;
using Microsoft.VisualStudio.LanguageServices.Implementation.EditAndContinue;
using Microsoft.VisualStudio.LanguageServices.Implementation.TaskList;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Interop;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册