Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Inline Rename: Prevent crash when source control dialogs show
Fixes https://devdiv.visualstudio.com/DevDiv/_workitems?_a=edit&id=227513 InlineRenameSession.ApplyReplacementText is called in response to buffer changes. In response to these changes, we want to (1) kick off some background work to calculate the new ConflictResolutionTask, (2) propagate the new replacementText to all buffers on the UI thread, and then (3) apply the results of the ConflictResolutionTask on the UI thread once they're ready. Prior to this change, steps (1) and (3) were always done together, in sequence, regardless of how (2) was progressing. Since the replacementText propagation started synchronously and stayed on the UI thread, this usually meant that the application of the results of the ConflictResolutionTask would have to wait until the replacementText propagation completed (because it would wait for the UI thread to be available). This worked great, most of the time. But, if the propagation of the replacementText causes a buffer change in a source controlled document and "Prompt for Checkout" is enabled, then a modal dialog to checkout files appears. Then, the UI thread pumps and allows more work to be scheduled there. Our ConflictResolutionTask could finish calculating conflicts and the application of these conflicts could be scheduled on the UI thread while a dialog is still up (and we are still propagating the replacementText). It would then try to manipulate the undo stack and apply edits to buffers. Since we still have an open undo transaction from the replacementText propagation, the attempt to manipulate the undo stack would crash. This change splits the kicking off of the ConflictResolutionTask and the application of the replacements it computes into separately callable methods that aren't automatically chained together. In some cases they can be called in sequence, emulating the old behavior. But when a text buffer edit triggers ApplyReplacementText, we first kick off the ConflictResolutionTask, then propagate the new replacementText, and *then*, once the replacementText is fully propagated (including the handling of any source control modal dialogs), we finally apply the results of the ConflictResolutionTask on the UI thread. This does not guarantee that *no* reentrancy will ever happen in Inline Rename, but it gets rid of the biggest, obvious culprit. Completely safeguarding would require a larger change, and I think this approach is the best one given our current RTM escrow timeline, and it will fix the problem for the vast majority of users encountering this problem.
- Loading branch information