From 98e4e84769c39c3c5f9b696f335d9950c3566a69 Mon Sep 17 00:00:00 2001 From: HeeJae Chang Date: Fri, 1 Mar 2019 14:29:00 -0800 Subject: [PATCH 1/2] added ability to clear all diagnostics reproted from a IDiagnosticUpdateSource previously IDiagnosticUpdateSource has to clear each diagnostics it reported group by group. that was fine for IDiagnosticUpdateSource that supports incremental update, but some source such as EditAndContinue doesn't support incremental update since their errors (emit errors) come and go as a bulk (whole project). when they update, they need to update everything. so tracking things in group for incremental update is unnecessary for such source. the new API (Source.Cleared) make it easy for source to clear all diagnostics at once it produced. --- .../EditAndContinueDiagnosticUpdateSource.cs | 1 + .../Diagnostics/DiagnosticServiceTests.cs | 68 +++++++++++++++++++ .../AbstractSquiggleProducerTests.cs | 1 + .../AbstractHostDiagnosticUpdateSource.cs | 1 + .../DefaultDiagnosticAnalyzerService.cs | 1 + .../DiagnosticAnalyzerService_UpdateSource.cs | 13 ++++ .../Portable/Diagnostics/DiagnosticService.cs | 67 ++++++++++++++++++ ...Service_UpdateSourceRegistrationService.cs | 2 + .../Diagnostics/IDiagnosticUpdateSource.cs | 5 ++ .../ExternalErrorDiagnosticUpdateSource.cs | 1 + .../ExternalDiagnosticUpdateSourceTests.vb | 1 + .../EditAndContinueTestHelper.vb | 1 + .../Portable/Diagnostics/DiagnosticData.cs | 1 - 13 files changed, 162 insertions(+), 1 deletion(-) diff --git a/src/EditorFeatures/Core/Implementation/EditAndContinue/EditAndContinueDiagnosticUpdateSource.cs b/src/EditorFeatures/Core/Implementation/EditAndContinue/EditAndContinueDiagnosticUpdateSource.cs index c6ba95855dbfd..c769dcebd84ed 100644 --- a/src/EditorFeatures/Core/Implementation/EditAndContinue/EditAndContinueDiagnosticUpdateSource.cs +++ b/src/EditorFeatures/Core/Implementation/EditAndContinue/EditAndContinueDiagnosticUpdateSource.cs @@ -40,6 +40,7 @@ public EditAndContinueDiagnosticUpdateSource(IDiagnosticUpdateSourceRegistration public bool SupportGetDiagnostics => false; public event EventHandler DiagnosticsUpdated; + public event EventHandler Cleared { add { } remove { } } public ImmutableArray GetDiagnostics(Workspace workspace, ProjectId projectId, DocumentId documentId, object id, bool includeSuppressedDiagnostics = false, CancellationToken cancellationToken = default) { diff --git a/src/EditorFeatures/Test/Diagnostics/DiagnosticServiceTests.cs b/src/EditorFeatures/Test/Diagnostics/DiagnosticServiceTests.cs index 5e1f343a24466..aa65eb8a77dc7 100644 --- a/src/EditorFeatures/Test/Diagnostics/DiagnosticServiceTests.cs +++ b/src/EditorFeatures/Test/Diagnostics/DiagnosticServiceTests.cs @@ -90,6 +90,68 @@ public void TestGetDiagnostics2() } } + [Fact, Trait(Traits.Feature, Traits.Features.Diagnostics)] + public void TestCleared() + { + using (var workspace = new TestWorkspace(TestExportProvider.ExportProviderWithCSharpAndVisualBasic)) + { + var set = new ManualResetEvent(false); + var document = workspace.CurrentSolution.AddProject("TestProject", "TestProject", LanguageNames.CSharp).AddDocument("TestDocument", string.Empty); + var document2 = document.Project.AddDocument("TestDocument2", string.Empty); + + var diagnosticService = new DiagnosticService(AsynchronousOperationListenerProvider.NullProvider); + + var source1 = new TestDiagnosticUpdateSource(support: false, diagnosticData: null); + diagnosticService.Register(source1); + + var source2 = new TestDiagnosticUpdateSource(support: false, diagnosticData: null); + diagnosticService.Register(source2); + + diagnosticService.DiagnosticsUpdated += MarkSet; + + // add bunch of data to the service for both sources + RaiseDiagnosticEvent(set, source1, workspace, document.Project.Id, document.Id, Tuple.Create(workspace, document)); + RaiseDiagnosticEvent(set, source1, workspace, document.Project.Id, document.Id, Tuple.Create(workspace, document.Project, document)); + RaiseDiagnosticEvent(set, source1, workspace, document2.Project.Id, document2.Id, Tuple.Create(workspace, document2)); + + RaiseDiagnosticEvent(set, source2, workspace, document.Project.Id, null, Tuple.Create(workspace, document.Project)); + RaiseDiagnosticEvent(set, source2, workspace, null, null, Tuple.Create(workspace)); + + // confirm data is there. + var data1 = diagnosticService.GetDiagnostics(workspace, null, null, null, false, CancellationToken.None); + Assert.Equal(5, data1.Count()); + + diagnosticService.DiagnosticsUpdated -= MarkSet; + + // confirm clear for a source + set.Reset(); + var count = 0; + diagnosticService.DiagnosticsUpdated += MarkCalled; + + source1.RaiseClearedEvent(); + + set.WaitOne(); + + // confirm there are 2 data left + var data2 = diagnosticService.GetDiagnostics(workspace, null, null, null, false, CancellationToken.None); + Assert.Equal(2, data2.Count()); + + void MarkCalled(object sender, DiagnosticsUpdatedArgs args) + { + // event is serialized. no concurrent call + if (++count == 3) + { + set.Set(); + } + } + + void MarkSet(object sender, DiagnosticsUpdatedArgs args) + { + set.Set(); + } + } + } + private static DiagnosticData RaiseDiagnosticEvent(ManualResetEvent set, TestDiagnosticUpdateSource source, TestWorkspace workspace, ProjectId project, DocumentId document, object id) { set.Reset(); @@ -126,6 +188,7 @@ public TestDiagnosticUpdateSource(bool support, DiagnosticData[] diagnosticData) public bool SupportGetDiagnostics { get { return _support; } } public event EventHandler DiagnosticsUpdated; + public event EventHandler Cleared; public ImmutableArray GetDiagnostics(Workspace workspace, ProjectId projectId, DocumentId documentId, object id, bool includeSuppressedDiagnostics = false, CancellationToken cancellationToken = default) { @@ -136,6 +199,11 @@ public void RaiseUpdateEvent(DiagnosticsUpdatedArgs args) { DiagnosticsUpdated?.Invoke(this, args); } + + public void RaiseClearedEvent() + { + Cleared?.Invoke(this, EventArgs.Empty); + } } } } diff --git a/src/EditorFeatures/TestUtilities/Squiggles/AbstractSquiggleProducerTests.cs b/src/EditorFeatures/TestUtilities/Squiggles/AbstractSquiggleProducerTests.cs index 10775140a1579..aaffc57793fbd 100644 --- a/src/EditorFeatures/TestUtilities/Squiggles/AbstractSquiggleProducerTests.cs +++ b/src/EditorFeatures/TestUtilities/Squiggles/AbstractSquiggleProducerTests.cs @@ -89,6 +89,7 @@ public void RaiseDiagnosticsUpdated(DiagnosticsUpdatedArgs args) } public event EventHandler DiagnosticsUpdated; + public event EventHandler Cleared { add { } remove { } } public bool SupportGetDiagnostics => false; diff --git a/src/Features/Core/Portable/Diagnostics/AbstractHostDiagnosticUpdateSource.cs b/src/Features/Core/Portable/Diagnostics/AbstractHostDiagnosticUpdateSource.cs index 9eecd44fdc285..d72a06ddf9ef5 100644 --- a/src/Features/Core/Portable/Diagnostics/AbstractHostDiagnosticUpdateSource.cs +++ b/src/Features/Core/Portable/Diagnostics/AbstractHostDiagnosticUpdateSource.cs @@ -28,6 +28,7 @@ public ImmutableArray GetDiagnostics(Workspace workspace, Projec } public event EventHandler DiagnosticsUpdated; + public event EventHandler Cleared { add { } remove { } } public void RaiseDiagnosticsUpdated(DiagnosticsUpdatedArgs args) { diff --git a/src/Features/Core/Portable/Diagnostics/DefaultDiagnosticAnalyzerService.cs b/src/Features/Core/Portable/Diagnostics/DefaultDiagnosticAnalyzerService.cs index baf725521cf52..24a0e36498ae2 100644 --- a/src/Features/Core/Portable/Diagnostics/DefaultDiagnosticAnalyzerService.cs +++ b/src/Features/Core/Portable/Diagnostics/DefaultDiagnosticAnalyzerService.cs @@ -40,6 +40,7 @@ public IIncrementalAnalyzer CreateIncrementalAnalyzer(Workspace workspace) } public event EventHandler DiagnosticsUpdated; + public event EventHandler Cleared { add { } remove { } } // this only support push model, pull model will be provided by DiagnosticService by caching everything this one pushed public bool SupportGetDiagnostics => false; diff --git a/src/Features/Core/Portable/Diagnostics/DiagnosticAnalyzerService_UpdateSource.cs b/src/Features/Core/Portable/Diagnostics/DiagnosticAnalyzerService_UpdateSource.cs index cecc609ead01b..24c97a81bedf4 100644 --- a/src/Features/Core/Portable/Diagnostics/DiagnosticAnalyzerService_UpdateSource.cs +++ b/src/Features/Core/Portable/Diagnostics/DiagnosticAnalyzerService_UpdateSource.cs @@ -43,6 +43,19 @@ public event EventHandler DiagnosticsUpdated } } + public event EventHandler Cleared + { + add + { + // don't do anything. this update source doesn't use cleared event + } + + remove + { + // don't do anything. this update source doesn't use cleared event + } + } + internal void RaiseDiagnosticsUpdated(DiagnosticsUpdatedArgs args) { // all diagnostics events are serialized. diff --git a/src/Features/Core/Portable/Diagnostics/DiagnosticService.cs b/src/Features/Core/Portable/Diagnostics/DiagnosticService.cs index b8fcf82da1e14..da3df8ea81dba 100644 --- a/src/Features/Core/Portable/Diagnostics/DiagnosticService.cs +++ b/src/Features/Core/Portable/Diagnostics/DiagnosticService.cs @@ -79,6 +79,37 @@ private void RaiseDiagnosticsUpdated(object sender, DiagnosticsUpdatedArgs args) }).CompletesAsyncOperation(eventToken); } + private void RaiseDiagnosticsCleared(object sender) + { + Contract.ThrowIfNull(sender); + var source = (IDiagnosticUpdateSource)sender; + + var ev = _eventMap.GetEventHandlers>(DiagnosticsUpdatedEventName); + if (!RequireRunningEventTasks(source, ev)) + { + return; + } + + var eventToken = _listener.BeginAsyncOperation(DiagnosticsUpdatedEventName); + _eventQueue.ScheduleTask(() => + { + using (var pooledObject = SharedPools.Default>().GetPooledObject()) + { + var removed = pooledObject.Object; + if (!ClearDiagnosticsFromDataMapFor(source, removed)) + { + // there is no change, nothing to raise events for. + return; + } + + foreach (var args in removed) + { + ev.RaiseEvent(handler => handler(sender, args)); + } + } + }).CompletesAsyncOperation(eventToken); + } + private bool RequireRunningEventTasks( IDiagnosticUpdateSource source, EventMap.EventHandlerSet> ev) { @@ -150,12 +181,48 @@ private bool UpdateDataMap(IDiagnosticUpdateSource source, DiagnosticsUpdatedArg } } + private bool ClearDiagnosticsFromDataMapFor(IDiagnosticUpdateSource source, List removed) + { + // we expect source who uses this ability to have small number of diagnostics. + lock (_gate) + { + Debug.Assert(_updateSources.Contains(source)); + + // 2 different workspaces (ex, PreviewWorkspaces) can return same Args.Id, we need to + // distinguish them. so we separate diagnostics per workspace map. + if (!_map.TryGetValue(source, out var workspaceMap)) + { + return false; + } + + foreach (var (workspace, map) in workspaceMap) + { + foreach (var (id, data) in map) + { + removed.Add(DiagnosticsUpdatedArgs.DiagnosticsRemoved(id, data.Workspace, solution: null, data.ProjectId, data.DocumentId)); + } + } + + // all diagnostics from the source is cleared + _map.Remove(source); + return true; + } + } + private void OnDiagnosticsUpdated(object sender, DiagnosticsUpdatedArgs e) { AssertIfNull(e.Diagnostics); + + // all events are serialized by async event handler RaiseDiagnosticsUpdated(sender, e); } + private void OnCleared(object sender, EventArgs e) + { + // all events are serialized by async event handler + RaiseDiagnosticsCleared(sender); + } + public IEnumerable GetDiagnostics( Workspace workspace, ProjectId projectId, DocumentId documentId, object id, bool includeSuppressedDiagnostics, CancellationToken cancellationToken) { diff --git a/src/Features/Core/Portable/Diagnostics/DiagnosticService_UpdateSourceRegistrationService.cs b/src/Features/Core/Portable/Diagnostics/DiagnosticService_UpdateSourceRegistrationService.cs index 9a60783de5ed2..37cbbd2849c58 100644 --- a/src/Features/Core/Portable/Diagnostics/DiagnosticService_UpdateSourceRegistrationService.cs +++ b/src/Features/Core/Portable/Diagnostics/DiagnosticService_UpdateSourceRegistrationService.cs @@ -28,7 +28,9 @@ public void Register(IDiagnosticUpdateSource source) } _updateSources = _updateSources.Add(source); + source.DiagnosticsUpdated += OnDiagnosticsUpdated; + source.Cleared += OnCleared; } } } diff --git a/src/Features/Core/Portable/Diagnostics/IDiagnosticUpdateSource.cs b/src/Features/Core/Portable/Diagnostics/IDiagnosticUpdateSource.cs index fc770270d8903..631e2d9612f56 100644 --- a/src/Features/Core/Portable/Diagnostics/IDiagnosticUpdateSource.cs +++ b/src/Features/Core/Portable/Diagnostics/IDiagnosticUpdateSource.cs @@ -16,6 +16,11 @@ internal interface IDiagnosticUpdateSource /// event EventHandler DiagnosticsUpdated; + /// + /// Raise this when all diagnostics reported from this update source has cleared + /// + event EventHandler Cleared; + /// /// Return true if the source supports GetDiagnostics API otherwise, return false so that the engine can cache data from DiagnosticsUpdated in memory /// diff --git a/src/VisualStudio/Core/Def/Implementation/TaskList/ExternalErrorDiagnosticUpdateSource.cs b/src/VisualStudio/Core/Def/Implementation/TaskList/ExternalErrorDiagnosticUpdateSource.cs index 4ae7e4c35806e..d72b357b80644 100644 --- a/src/VisualStudio/Core/Def/Implementation/TaskList/ExternalErrorDiagnosticUpdateSource.cs +++ b/src/VisualStudio/Core/Def/Implementation/TaskList/ExternalErrorDiagnosticUpdateSource.cs @@ -76,6 +76,7 @@ internal ExternalErrorDiagnosticUpdateSource( public event EventHandler BuildStarted; public event EventHandler DiagnosticsUpdated; + public event EventHandler Cleared { add { } remove { } } public bool IsInProgress => BuildInprogressState != null; diff --git a/src/VisualStudio/Core/Test/Diagnostics/ExternalDiagnosticUpdateSourceTests.vb b/src/VisualStudio/Core/Test/Diagnostics/ExternalDiagnosticUpdateSourceTests.vb index 4e5e775fe46bc..07287c8dc1ec8 100644 --- a/src/VisualStudio/Core/Test/Diagnostics/ExternalDiagnosticUpdateSourceTests.vb +++ b/src/VisualStudio/Core/Test/Diagnostics/ExternalDiagnosticUpdateSourceTests.vb @@ -346,6 +346,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.Diagnostics End Property Public Event DiagnosticsUpdated As EventHandler(Of DiagnosticsUpdatedArgs) Implements IDiagnosticUpdateSource.DiagnosticsUpdated + Public Event Cleared As EventHandler Implements IDiagnosticUpdateSource.Cleared Public Function GetDiagnostics(workspace As Microsoft.CodeAnalysis.Workspace, projectId As ProjectId, documentId As DocumentId, id As Object, includeSuppressedDiagnostics As Boolean, cancellationToken As CancellationToken) As ImmutableArray(Of DiagnosticData) Implements IDiagnosticUpdateSource.GetDiagnostics Return If(includeSuppressedDiagnostics, _data, _data.WhereAsArray(Function(d) Not d.IsSuppressed)) diff --git a/src/VisualStudio/Core/Test/EditAndContinue/EditAndContinueTestHelper.vb b/src/VisualStudio/Core/Test/EditAndContinue/EditAndContinueTestHelper.vb index 7e8a37df14742..ed66b5532cc42 100644 --- a/src/VisualStudio/Core/Test/EditAndContinue/EditAndContinueTestHelper.vb +++ b/src/VisualStudio/Core/Test/EditAndContinue/EditAndContinueTestHelper.vb @@ -43,6 +43,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.EditAndContinue End Property Public Event DiagnosticsUpdated As EventHandler(Of DiagnosticsUpdatedArgs) Implements IDiagnosticUpdateSource.DiagnosticsUpdated + Public Event Cleared As EventHandler Implements IDiagnosticUpdateSource.Cleared Public Function GetDiagnostics(workspace As Microsoft.CodeAnalysis.Workspace, projectId As ProjectId, documentId As DocumentId, id As Object, includeSuppressedDiagnostics As Boolean, cancellationToken As CancellationToken) As ImmutableArray(Of DiagnosticData) Implements IDiagnosticUpdateSource.GetDiagnostics Return If(includeSuppressedDiagnostics, _data, _data.WhereAsArray(Function(d) Not d.IsSuppressed)) diff --git a/src/Workspaces/Core/Portable/Diagnostics/DiagnosticData.cs b/src/Workspaces/Core/Portable/Diagnostics/DiagnosticData.cs index 9b775ac2cef41..e557e50cbc1a1 100644 --- a/src/Workspaces/Core/Portable/Diagnostics/DiagnosticData.cs +++ b/src/Workspaces/Core/Portable/Diagnostics/DiagnosticData.cs @@ -444,7 +444,6 @@ private static ImmutableDictionary GetProperties( return additionalProperties == null ? properties : properties.AddRange(additionalProperties); - throw new NotImplementedException(); } /// From c75be06bec44cc25ec6cff5cfbdd63c3e274c38a Mon Sep 17 00:00:00 2001 From: HeeJae Chang Date: Sat, 2 Mar 2019 01:33:29 -0800 Subject: [PATCH 2/2] addressing PR feedbacks --- .../EditAndContinueDiagnosticUpdateSource.cs | 2 +- .../Diagnostics/DiagnosticServiceTests.cs | 52 +++++++++---------- .../AbstractSquiggleProducerTests.cs | 2 +- .../AbstractHostDiagnosticUpdateSource.cs | 2 +- .../DefaultDiagnosticAnalyzerService.cs | 2 +- .../DiagnosticAnalyzerService_UpdateSource.cs | 2 +- .../Portable/Diagnostics/DiagnosticService.cs | 22 +++----- ...Service_UpdateSourceRegistrationService.cs | 2 +- .../Diagnostics/IDiagnosticUpdateSource.cs | 2 +- .../ExternalErrorDiagnosticUpdateSource.cs | 2 +- .../ExternalDiagnosticUpdateSourceTests.vb | 2 +- .../EditAndContinueTestHelper.vb | 2 +- 12 files changed, 44 insertions(+), 50 deletions(-) diff --git a/src/EditorFeatures/Core/Implementation/EditAndContinue/EditAndContinueDiagnosticUpdateSource.cs b/src/EditorFeatures/Core/Implementation/EditAndContinue/EditAndContinueDiagnosticUpdateSource.cs index c769dcebd84ed..18ea30e5f1b62 100644 --- a/src/EditorFeatures/Core/Implementation/EditAndContinue/EditAndContinueDiagnosticUpdateSource.cs +++ b/src/EditorFeatures/Core/Implementation/EditAndContinue/EditAndContinueDiagnosticUpdateSource.cs @@ -40,7 +40,7 @@ public EditAndContinueDiagnosticUpdateSource(IDiagnosticUpdateSourceRegistration public bool SupportGetDiagnostics => false; public event EventHandler DiagnosticsUpdated; - public event EventHandler Cleared { add { } remove { } } + public event EventHandler DiagnosticsCleared { add { } remove { } } public ImmutableArray GetDiagnostics(Workspace workspace, ProjectId projectId, DocumentId documentId, object id, bool includeSuppressedDiagnostics = false, CancellationToken cancellationToken = default) { diff --git a/src/EditorFeatures/Test/Diagnostics/DiagnosticServiceTests.cs b/src/EditorFeatures/Test/Diagnostics/DiagnosticServiceTests.cs index aa65eb8a77dc7..c931f18a067e8 100644 --- a/src/EditorFeatures/Test/Diagnostics/DiagnosticServiceTests.cs +++ b/src/EditorFeatures/Test/Diagnostics/DiagnosticServiceTests.cs @@ -20,17 +20,17 @@ public void TestGetDiagnostics1() { using (var workspace = new TestWorkspace(TestExportProvider.ExportProviderWithCSharpAndVisualBasic)) { - var set = new ManualResetEvent(false); + var mutex = new ManualResetEvent(false); var document = workspace.CurrentSolution.AddProject("TestProject", "TestProject", LanguageNames.CSharp).AddDocument("TestDocument", string.Empty); var source = new TestDiagnosticUpdateSource(false, null); var diagnosticService = new DiagnosticService(AsynchronousOperationListenerProvider.NullProvider); diagnosticService.Register(source); - diagnosticService.DiagnosticsUpdated += (s, o) => { set.Set(); }; + diagnosticService.DiagnosticsUpdated += (s, o) => { mutex.Set(); }; var id = Tuple.Create(workspace, document); - var diagnostic = RaiseDiagnosticEvent(set, source, workspace, document.Project.Id, document.Id, id); + var diagnostic = RaiseDiagnosticEvent(mutex, source, workspace, document.Project.Id, document.Id, id); var data1 = diagnosticService.GetDiagnostics(workspace, null, null, null, false, CancellationToken.None); Assert.Equal(diagnostic, data1.Single()); @@ -51,7 +51,7 @@ public void TestGetDiagnostics2() { using (var workspace = new TestWorkspace(TestExportProvider.ExportProviderWithCSharpAndVisualBasic)) { - var set = new ManualResetEvent(false); + var mutex = new ManualResetEvent(false); var document = workspace.CurrentSolution.AddProject("TestProject", "TestProject", LanguageNames.CSharp).AddDocument("TestDocument", string.Empty); var document2 = document.Project.AddDocument("TestDocument2", string.Empty); @@ -59,19 +59,19 @@ public void TestGetDiagnostics2() var diagnosticService = new DiagnosticService(AsynchronousOperationListenerProvider.NullProvider); diagnosticService.Register(source); - diagnosticService.DiagnosticsUpdated += (s, o) => { set.Set(); }; + diagnosticService.DiagnosticsUpdated += (s, o) => { mutex.Set(); }; var id = Tuple.Create(workspace, document); - RaiseDiagnosticEvent(set, source, workspace, document.Project.Id, document.Id, id); + RaiseDiagnosticEvent(mutex, source, workspace, document.Project.Id, document.Id, id); var id2 = Tuple.Create(workspace, document.Project, document); - RaiseDiagnosticEvent(set, source, workspace, document.Project.Id, document.Id, id2); + RaiseDiagnosticEvent(mutex, source, workspace, document.Project.Id, document.Id, id2); - RaiseDiagnosticEvent(set, source, workspace, document2.Project.Id, document2.Id, Tuple.Create(workspace, document2)); + RaiseDiagnosticEvent(mutex, source, workspace, document2.Project.Id, document2.Id, Tuple.Create(workspace, document2)); var id3 = Tuple.Create(workspace, document.Project); - RaiseDiagnosticEvent(set, source, workspace, document.Project.Id, null, id3); - RaiseDiagnosticEvent(set, source, workspace, null, null, Tuple.Create(workspace)); + RaiseDiagnosticEvent(mutex, source, workspace, document.Project.Id, null, id3); + RaiseDiagnosticEvent(mutex, source, workspace, null, null, Tuple.Create(workspace)); var data1 = diagnosticService.GetDiagnostics(workspace, null, null, null, false, CancellationToken.None); Assert.Equal(5, data1.Count()); @@ -95,7 +95,7 @@ public void TestCleared() { using (var workspace = new TestWorkspace(TestExportProvider.ExportProviderWithCSharpAndVisualBasic)) { - var set = new ManualResetEvent(false); + var mutex = new ManualResetEvent(false); var document = workspace.CurrentSolution.AddProject("TestProject", "TestProject", LanguageNames.CSharp).AddDocument("TestDocument", string.Empty); var document2 = document.Project.AddDocument("TestDocument2", string.Empty); @@ -110,12 +110,12 @@ public void TestCleared() diagnosticService.DiagnosticsUpdated += MarkSet; // add bunch of data to the service for both sources - RaiseDiagnosticEvent(set, source1, workspace, document.Project.Id, document.Id, Tuple.Create(workspace, document)); - RaiseDiagnosticEvent(set, source1, workspace, document.Project.Id, document.Id, Tuple.Create(workspace, document.Project, document)); - RaiseDiagnosticEvent(set, source1, workspace, document2.Project.Id, document2.Id, Tuple.Create(workspace, document2)); + RaiseDiagnosticEvent(mutex, source1, workspace, document.Project.Id, document.Id, Tuple.Create(workspace, document)); + RaiseDiagnosticEvent(mutex, source1, workspace, document.Project.Id, document.Id, Tuple.Create(workspace, document.Project, document)); + RaiseDiagnosticEvent(mutex, source1, workspace, document2.Project.Id, document2.Id, Tuple.Create(workspace, document2)); - RaiseDiagnosticEvent(set, source2, workspace, document.Project.Id, null, Tuple.Create(workspace, document.Project)); - RaiseDiagnosticEvent(set, source2, workspace, null, null, Tuple.Create(workspace)); + RaiseDiagnosticEvent(mutex, source2, workspace, document.Project.Id, null, Tuple.Create(workspace, document.Project)); + RaiseDiagnosticEvent(mutex, source2, workspace, null, null, Tuple.Create(workspace)); // confirm data is there. var data1 = diagnosticService.GetDiagnostics(workspace, null, null, null, false, CancellationToken.None); @@ -124,13 +124,13 @@ public void TestCleared() diagnosticService.DiagnosticsUpdated -= MarkSet; // confirm clear for a source - set.Reset(); + mutex.Reset(); var count = 0; diagnosticService.DiagnosticsUpdated += MarkCalled; - source1.RaiseClearedEvent(); + source1.RaiseDiagnosticsClearedEvent(); - set.WaitOne(); + mutex.WaitOne(); // confirm there are 2 data left var data2 = diagnosticService.GetDiagnostics(workspace, null, null, null, false, CancellationToken.None); @@ -141,13 +141,13 @@ void MarkCalled(object sender, DiagnosticsUpdatedArgs args) // event is serialized. no concurrent call if (++count == 3) { - set.Set(); + mutex.Set(); } } void MarkSet(object sender, DiagnosticsUpdatedArgs args) { - set.Set(); + mutex.Set(); } } } @@ -158,7 +158,7 @@ private static DiagnosticData RaiseDiagnosticEvent(ManualResetEvent set, TestDia var diagnostic = CreateDiagnosticData(workspace, project, document); - source.RaiseUpdateEvent( + source.RaiseDiagnosticsUpdatedEvent( DiagnosticsUpdatedArgs.DiagnosticsCreated(id, workspace, workspace.CurrentSolution, project, document, ImmutableArray.Create(diagnostic))); set.WaitOne(); @@ -188,21 +188,21 @@ public TestDiagnosticUpdateSource(bool support, DiagnosticData[] diagnosticData) public bool SupportGetDiagnostics { get { return _support; } } public event EventHandler DiagnosticsUpdated; - public event EventHandler Cleared; + public event EventHandler DiagnosticsCleared; public ImmutableArray GetDiagnostics(Workspace workspace, ProjectId projectId, DocumentId documentId, object id, bool includeSuppressedDiagnostics = false, CancellationToken cancellationToken = default) { return _support ? _diagnosticData : ImmutableArray.Empty; } - public void RaiseUpdateEvent(DiagnosticsUpdatedArgs args) + public void RaiseDiagnosticsUpdatedEvent(DiagnosticsUpdatedArgs args) { DiagnosticsUpdated?.Invoke(this, args); } - public void RaiseClearedEvent() + public void RaiseDiagnosticsClearedEvent() { - Cleared?.Invoke(this, EventArgs.Empty); + DiagnosticsCleared?.Invoke(this, EventArgs.Empty); } } } diff --git a/src/EditorFeatures/TestUtilities/Squiggles/AbstractSquiggleProducerTests.cs b/src/EditorFeatures/TestUtilities/Squiggles/AbstractSquiggleProducerTests.cs index aaffc57793fbd..1f3331d335f4f 100644 --- a/src/EditorFeatures/TestUtilities/Squiggles/AbstractSquiggleProducerTests.cs +++ b/src/EditorFeatures/TestUtilities/Squiggles/AbstractSquiggleProducerTests.cs @@ -89,7 +89,7 @@ public void RaiseDiagnosticsUpdated(DiagnosticsUpdatedArgs args) } public event EventHandler DiagnosticsUpdated; - public event EventHandler Cleared { add { } remove { } } + public event EventHandler DiagnosticsCleared { add { } remove { } } public bool SupportGetDiagnostics => false; diff --git a/src/Features/Core/Portable/Diagnostics/AbstractHostDiagnosticUpdateSource.cs b/src/Features/Core/Portable/Diagnostics/AbstractHostDiagnosticUpdateSource.cs index d72a06ddf9ef5..6a2729d875c7e 100644 --- a/src/Features/Core/Portable/Diagnostics/AbstractHostDiagnosticUpdateSource.cs +++ b/src/Features/Core/Portable/Diagnostics/AbstractHostDiagnosticUpdateSource.cs @@ -28,7 +28,7 @@ public ImmutableArray GetDiagnostics(Workspace workspace, Projec } public event EventHandler DiagnosticsUpdated; - public event EventHandler Cleared { add { } remove { } } + public event EventHandler DiagnosticsCleared { add { } remove { } } public void RaiseDiagnosticsUpdated(DiagnosticsUpdatedArgs args) { diff --git a/src/Features/Core/Portable/Diagnostics/DefaultDiagnosticAnalyzerService.cs b/src/Features/Core/Portable/Diagnostics/DefaultDiagnosticAnalyzerService.cs index 24a0e36498ae2..b497fd2347816 100644 --- a/src/Features/Core/Portable/Diagnostics/DefaultDiagnosticAnalyzerService.cs +++ b/src/Features/Core/Portable/Diagnostics/DefaultDiagnosticAnalyzerService.cs @@ -40,7 +40,7 @@ public IIncrementalAnalyzer CreateIncrementalAnalyzer(Workspace workspace) } public event EventHandler DiagnosticsUpdated; - public event EventHandler Cleared { add { } remove { } } + public event EventHandler DiagnosticsCleared { add { } remove { } } // this only support push model, pull model will be provided by DiagnosticService by caching everything this one pushed public bool SupportGetDiagnostics => false; diff --git a/src/Features/Core/Portable/Diagnostics/DiagnosticAnalyzerService_UpdateSource.cs b/src/Features/Core/Portable/Diagnostics/DiagnosticAnalyzerService_UpdateSource.cs index 24c97a81bedf4..9553d1430f705 100644 --- a/src/Features/Core/Portable/Diagnostics/DiagnosticAnalyzerService_UpdateSource.cs +++ b/src/Features/Core/Portable/Diagnostics/DiagnosticAnalyzerService_UpdateSource.cs @@ -43,7 +43,7 @@ public event EventHandler DiagnosticsUpdated } } - public event EventHandler Cleared + public event EventHandler DiagnosticsCleared { add { diff --git a/src/Features/Core/Portable/Diagnostics/DiagnosticService.cs b/src/Features/Core/Portable/Diagnostics/DiagnosticService.cs index da3df8ea81dba..9c26b1353558d 100644 --- a/src/Features/Core/Portable/Diagnostics/DiagnosticService.cs +++ b/src/Features/Core/Portable/Diagnostics/DiagnosticService.cs @@ -55,11 +55,8 @@ public event EventHandler DiagnosticsUpdated } } - private void RaiseDiagnosticsUpdated(object sender, DiagnosticsUpdatedArgs args) + private void RaiseDiagnosticsUpdated(IDiagnosticUpdateSource source, DiagnosticsUpdatedArgs args) { - Contract.ThrowIfNull(sender); - var source = (IDiagnosticUpdateSource)sender; - var ev = _eventMap.GetEventHandlers>(DiagnosticsUpdatedEventName); if (!RequireRunningEventTasks(source, ev)) { @@ -75,15 +72,12 @@ private void RaiseDiagnosticsUpdated(object sender, DiagnosticsUpdatedArgs args) return; } - ev.RaiseEvent(handler => handler(sender, args)); + ev.RaiseEvent(handler => handler(source, args)); }).CompletesAsyncOperation(eventToken); } - private void RaiseDiagnosticsCleared(object sender) + private void RaiseDiagnosticsCleared(IDiagnosticUpdateSource source) { - Contract.ThrowIfNull(sender); - var source = (IDiagnosticUpdateSource)sender; - var ev = _eventMap.GetEventHandlers>(DiagnosticsUpdatedEventName); if (!RequireRunningEventTasks(source, ev)) { @@ -96,7 +90,7 @@ private void RaiseDiagnosticsCleared(object sender) using (var pooledObject = SharedPools.Default>().GetPooledObject()) { var removed = pooledObject.Object; - if (!ClearDiagnosticsFromDataMapFor(source, removed)) + if (!ClearDiagnosticsReportedBySource(source, removed)) { // there is no change, nothing to raise events for. return; @@ -104,7 +98,7 @@ private void RaiseDiagnosticsCleared(object sender) foreach (var args in removed) { - ev.RaiseEvent(handler => handler(sender, args)); + ev.RaiseEvent(handler => handler(source, args)); } } }).CompletesAsyncOperation(eventToken); @@ -181,7 +175,7 @@ private bool UpdateDataMap(IDiagnosticUpdateSource source, DiagnosticsUpdatedArg } } - private bool ClearDiagnosticsFromDataMapFor(IDiagnosticUpdateSource source, List removed) + private bool ClearDiagnosticsReportedBySource(IDiagnosticUpdateSource source, List removed) { // we expect source who uses this ability to have small number of diagnostics. lock (_gate) @@ -214,13 +208,13 @@ private void OnDiagnosticsUpdated(object sender, DiagnosticsUpdatedArgs e) AssertIfNull(e.Diagnostics); // all events are serialized by async event handler - RaiseDiagnosticsUpdated(sender, e); + RaiseDiagnosticsUpdated((IDiagnosticUpdateSource)sender, e); } private void OnCleared(object sender, EventArgs e) { // all events are serialized by async event handler - RaiseDiagnosticsCleared(sender); + RaiseDiagnosticsCleared((IDiagnosticUpdateSource)sender); } public IEnumerable GetDiagnostics( diff --git a/src/Features/Core/Portable/Diagnostics/DiagnosticService_UpdateSourceRegistrationService.cs b/src/Features/Core/Portable/Diagnostics/DiagnosticService_UpdateSourceRegistrationService.cs index 37cbbd2849c58..3af973c48eacc 100644 --- a/src/Features/Core/Portable/Diagnostics/DiagnosticService_UpdateSourceRegistrationService.cs +++ b/src/Features/Core/Portable/Diagnostics/DiagnosticService_UpdateSourceRegistrationService.cs @@ -30,7 +30,7 @@ public void Register(IDiagnosticUpdateSource source) _updateSources = _updateSources.Add(source); source.DiagnosticsUpdated += OnDiagnosticsUpdated; - source.Cleared += OnCleared; + source.DiagnosticsCleared += OnCleared; } } } diff --git a/src/Features/Core/Portable/Diagnostics/IDiagnosticUpdateSource.cs b/src/Features/Core/Portable/Diagnostics/IDiagnosticUpdateSource.cs index 631e2d9612f56..30b11285d702f 100644 --- a/src/Features/Core/Portable/Diagnostics/IDiagnosticUpdateSource.cs +++ b/src/Features/Core/Portable/Diagnostics/IDiagnosticUpdateSource.cs @@ -19,7 +19,7 @@ internal interface IDiagnosticUpdateSource /// /// Raise this when all diagnostics reported from this update source has cleared /// - event EventHandler Cleared; + event EventHandler DiagnosticsCleared; /// /// Return true if the source supports GetDiagnostics API otherwise, return false so that the engine can cache data from DiagnosticsUpdated in memory diff --git a/src/VisualStudio/Core/Def/Implementation/TaskList/ExternalErrorDiagnosticUpdateSource.cs b/src/VisualStudio/Core/Def/Implementation/TaskList/ExternalErrorDiagnosticUpdateSource.cs index d72b357b80644..fee8e439c23a5 100644 --- a/src/VisualStudio/Core/Def/Implementation/TaskList/ExternalErrorDiagnosticUpdateSource.cs +++ b/src/VisualStudio/Core/Def/Implementation/TaskList/ExternalErrorDiagnosticUpdateSource.cs @@ -76,7 +76,7 @@ internal ExternalErrorDiagnosticUpdateSource( public event EventHandler BuildStarted; public event EventHandler DiagnosticsUpdated; - public event EventHandler Cleared { add { } remove { } } + public event EventHandler DiagnosticsCleared { add { } remove { } } public bool IsInProgress => BuildInprogressState != null; diff --git a/src/VisualStudio/Core/Test/Diagnostics/ExternalDiagnosticUpdateSourceTests.vb b/src/VisualStudio/Core/Test/Diagnostics/ExternalDiagnosticUpdateSourceTests.vb index 07287c8dc1ec8..afcf6d08c87ec 100644 --- a/src/VisualStudio/Core/Test/Diagnostics/ExternalDiagnosticUpdateSourceTests.vb +++ b/src/VisualStudio/Core/Test/Diagnostics/ExternalDiagnosticUpdateSourceTests.vb @@ -346,7 +346,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.Diagnostics End Property Public Event DiagnosticsUpdated As EventHandler(Of DiagnosticsUpdatedArgs) Implements IDiagnosticUpdateSource.DiagnosticsUpdated - Public Event Cleared As EventHandler Implements IDiagnosticUpdateSource.Cleared + Public Event DiagnosticsCleared As EventHandler Implements IDiagnosticUpdateSource.DiagnosticsCleared Public Function GetDiagnostics(workspace As Microsoft.CodeAnalysis.Workspace, projectId As ProjectId, documentId As DocumentId, id As Object, includeSuppressedDiagnostics As Boolean, cancellationToken As CancellationToken) As ImmutableArray(Of DiagnosticData) Implements IDiagnosticUpdateSource.GetDiagnostics Return If(includeSuppressedDiagnostics, _data, _data.WhereAsArray(Function(d) Not d.IsSuppressed)) diff --git a/src/VisualStudio/Core/Test/EditAndContinue/EditAndContinueTestHelper.vb b/src/VisualStudio/Core/Test/EditAndContinue/EditAndContinueTestHelper.vb index ed66b5532cc42..adfaac06a2c8d 100644 --- a/src/VisualStudio/Core/Test/EditAndContinue/EditAndContinueTestHelper.vb +++ b/src/VisualStudio/Core/Test/EditAndContinue/EditAndContinueTestHelper.vb @@ -43,7 +43,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.EditAndContinue End Property Public Event DiagnosticsUpdated As EventHandler(Of DiagnosticsUpdatedArgs) Implements IDiagnosticUpdateSource.DiagnosticsUpdated - Public Event Cleared As EventHandler Implements IDiagnosticUpdateSource.Cleared + Public Event DiagnosticsCleared As EventHandler Implements IDiagnosticUpdateSource.DiagnosticsCleared Public Function GetDiagnostics(workspace As Microsoft.CodeAnalysis.Workspace, projectId As ProjectId, documentId As DocumentId, id As Object, includeSuppressedDiagnostics As Boolean, cancellationToken As CancellationToken) As ImmutableArray(Of DiagnosticData) Implements IDiagnosticUpdateSource.GetDiagnostics Return If(includeSuppressedDiagnostics, _data, _data.WhereAsArray(Function(d) Not d.IsSuppressed))