From 399dcca4f2a6b4edfc882a6837c81a3d2a41dcd6 Mon Sep 17 00:00:00 2001 From: "N. Taylor Mullen" Date: Mon, 6 Nov 2017 15:52:34 -0800 Subject: [PATCH] Make Foreground dispatchable methods noop if parser is disposed. - Added tests to validate each of the new noopable methods. #1750 --- .../DefaultVisualStudioRazorParser.cs | 22 +++++++-- .../DefaultVisualStudioRazorParserTest.cs | 48 +++++++++++++++++++ 2 files changed, 66 insertions(+), 4 deletions(-) diff --git a/src/Microsoft.VisualStudio.Editor.Razor/DefaultVisualStudioRazorParser.cs b/src/Microsoft.VisualStudio.Editor.Razor/DefaultVisualStudioRazorParser.cs index dedcd3e3ce..816e21bbfe 100644 --- a/src/Microsoft.VisualStudio.Editor.Razor/DefaultVisualStudioRazorParser.cs +++ b/src/Microsoft.VisualStudio.Editor.Razor/DefaultVisualStudioRazorParser.cs @@ -38,6 +38,7 @@ namespace Microsoft.VisualStudio.Editor.Razor private RazorTemplateEngine _templateEngine; private RazorCodeDocument _codeDocument; private ITextSnapshot _snapshot; + private bool _disposed; // For testing only internal DefaultVisualStudioRazorParser(RazorCodeDocument codeDocument) @@ -127,6 +128,8 @@ namespace Microsoft.VisualStudio.Editor.Razor _documentTracker.ContextChanged -= DocumentTracker_ContextChanged; StopIdleTimer(); + + _disposed = true; } // Internal for testing @@ -264,10 +267,16 @@ namespace Microsoft.VisualStudio.Editor.Razor } } - private void OnIdle(object state) + // Internal for testing + internal void OnIdle(object state) { _dispatcher.AssertForegroundThread(); + if (_disposed) + { + return; + } + OnNotifyForegroundIdle(); foreach (var textView in _documentTracker.TextViews) @@ -283,13 +292,13 @@ namespace Microsoft.VisualStudio.Editor.Razor QueueReparse(); } - private void ReparseOnForeground(object state) + // Internal for testing + internal void ReparseOnForeground(object state) { _dispatcher.AssertForegroundThread(); - if (_parser == null) + if (_disposed) { - Debug.Fail("Reparse being attempted after the parser has been disposed."); return; } @@ -354,6 +363,11 @@ namespace Microsoft.VisualStudio.Editor.Razor { _dispatcher.AssertForegroundThread(); + if (_disposed) + { + return; + } + var args = (DocumentStructureChangedEventArgs)state; if (_latestChangeReference == null || // extra hardening !_latestChangeReference.IsAssociatedWith(args)) diff --git a/test/Microsoft.VisualStudio.Editor.Razor.Test/DefaultVisualStudioRazorParserTest.cs b/test/Microsoft.VisualStudio.Editor.Razor.Test/DefaultVisualStudioRazorParserTest.cs index 0ef27cad70..ecb42b2067 100644 --- a/test/Microsoft.VisualStudio.Editor.Razor.Test/DefaultVisualStudioRazorParserTest.cs +++ b/test/Microsoft.VisualStudio.Editor.Razor.Test/DefaultVisualStudioRazorParserTest.cs @@ -27,6 +27,54 @@ namespace Microsoft.VisualStudio.Editor.Razor return documentTracker; } + [ForegroundFact] + public void ReparseOnForeground_NoopsIfDisposed() + { + // Arrange + var parser = new DefaultVisualStudioRazorParser( + Dispatcher, + CreateDocumentTracker(), + Mock.Of(), + new DefaultErrorReporter(), + Mock.Of()); + parser.Dispose(); + + // Act & Assert + parser.ReparseOnForeground(null); + } + + [ForegroundFact] + public void OnIdle_NoopsIfDisposed() + { + // Arrange + var parser = new DefaultVisualStudioRazorParser( + Dispatcher, + CreateDocumentTracker(), + Mock.Of(), + new DefaultErrorReporter(), + Mock.Of()); + parser.Dispose(); + + // Act & Assert + parser.OnIdle(null); + } + + [ForegroundFact] + public void OnDocumentStructureChanged_NoopsIfDisposed() + { + // Arrange + var parser = new DefaultVisualStudioRazorParser( + Dispatcher, + CreateDocumentTracker(), + Mock.Of(), + new DefaultErrorReporter(), + Mock.Of()); + parser.Dispose(); + + // Act & Assert + parser.OnDocumentStructureChanged(new object()); + } + [ForegroundFact] public void OnDocumentStructureChanged_IgnoresEditsThatAreOld() {