-
Notifications
You must be signed in to change notification settings - Fork 4.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Migrate to Microsoft.VisualStudio.Threading #28781
Changes from 2 commits
cb37547
cf25962
fbbf10d
28103a3
1ab9e23
dc48c9b
95032b5
059cd2f
ac2cfcb
2c85db1
23c08dd
660762a
4aeda54
bda85ce
bec6816
cccd0d0
4088da9
89a9992
bb01d0e
dc15c56
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -59,7 +59,7 @@ public Searcher( | |
} | ||
} | ||
|
||
internal async void Search() | ||
internal async Task SearchAsync() | ||
{ | ||
try | ||
{ | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -149,7 +149,7 @@ private void StartSearch(INavigateToCallback callback, string searchValue, IImmu | |
kinds, | ||
_cancellationTokenSource.Token); | ||
|
||
searcher.Search(); | ||
_ = searcher.SearchAsync(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Doesn't this have an effect of silencing all exceptions? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ➡️ It's an intermediate step. VSTHRD110 deals with observing the result of asynchronous operations. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @sharwell intermediate step still needs fixing further? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @jasonmalinowski Covered under the VSTHRD110 follow-up issue. |
||
} | ||
|
||
private static INavigateToSearchService_RemoveInterfaceAboveAndRenameThisAfterInternalsVisibleToUsersUpdate TryGetNavigateToSearchService(Project project) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,6 +5,7 @@ | |
using System.ComponentModel.Composition; | ||
using System.Linq; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
using Microsoft.CodeAnalysis.Editor.FindUsages; | ||
using Microsoft.CodeAnalysis.Editor.Host; | ||
using Microsoft.CodeAnalysis.Editor.Shared.Extensions; | ||
|
@@ -90,7 +91,7 @@ private bool TryExecuteCommand(int caretPosition, Document document, CommandExec | |
// a presenter that can accept streamed results. | ||
if (streamingService != null && streamingPresenter != null) | ||
{ | ||
StreamingFindReferences(document, caretPosition, streamingService, streamingPresenter); | ||
_ = StreamingFindReferencesAsync(document, caretPosition, streamingService, streamingPresenter); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why are we dropping a Task here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ➡️ This is part of the VSTHRD110 follow-up item mentioned in the original description. I also filed microsoft/vs-threading#345 to ensure we don't accidentally fail to address this. |
||
return true; | ||
} | ||
|
||
|
@@ -109,14 +110,14 @@ private IStreamingFindUsagesPresenter GetStreamingPresenter() | |
} | ||
} | ||
|
||
private async void StreamingFindReferences( | ||
private async Task StreamingFindReferencesAsync( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same comment as above. it seems better here to be async-void, to indicate that this is fire-and-forget. Namely, it helps ensure that this code knows that i needs to handle cancellation/exceptions. With Task-Returning, someone could easily remove the try/catch thinking it isn't necessary. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ➡️ Fire-and-forget falls under the umbrella of the VSTHRD110 follow-up item, for which we will soon have analyzer enforcement. The complexity drawbacks of correct use of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Sorry:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ➡️ Moved this discussion to #28781 (comment) |
||
Document document, int caretPosition, | ||
IFindUsagesService findUsagesService, | ||
IStreamingFindUsagesPresenter presenter) | ||
{ | ||
try | ||
{ | ||
using (var token = _asyncListener.BeginAsyncOperation(nameof(StreamingFindReferences))) | ||
using (var token = _asyncListener.BeginAsyncOperation(nameof(StreamingFindReferencesAsync))) | ||
{ | ||
// Let the presented know we're starting a search. It will give us back | ||
// the context object that the FAR service will push results into. | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -139,9 +139,11 @@ public void EndTracking() | |
} | ||
|
||
private void DocumentOpened(object sender, DocumentEventArgs e) | ||
=> DocumentOpenedAsync(e.Document); | ||
{ | ||
_ = DocumentOpenedAsync(e.Document); | ||
} | ||
|
||
private async void DocumentOpenedAsync(Document document) | ||
private async Task DocumentOpenedAsync(Document document) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same comment as above. being Task returning feels highly misleading and error prone. We've had people do this and not then handle cancellation/exceptions properly. 'async void' is a nice clear marker of "this is fire and forget, just async, no one will await, so you have to handle these cases yourself". There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ➡️ Covered by fire-and-forget umbrella. |
||
{ | ||
try | ||
{ | ||
|
@@ -232,12 +234,12 @@ private void TrackActiveSpansNoLock( | |
SetTrackingSpansNoLock(document.Id, null); | ||
|
||
// fire and forget: | ||
RefreshTrackingSpansAsync(document, snapshot); | ||
_ = RefreshTrackingSpansAsync(document, snapshot); | ||
} | ||
} | ||
} | ||
|
||
private async void RefreshTrackingSpansAsync(Document document, ITextSnapshot snapshot) | ||
private async Task RefreshTrackingSpansAsync(Document document, ITextSnapshot snapshot) | ||
{ | ||
try | ||
{ | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -101,7 +101,12 @@ private async Task AnalyzeAsync() | |
} | ||
} | ||
|
||
public async void Unregister(Workspace workspace, bool blockingShutdown = false) | ||
public void Unregister(Workspace workspace, bool blockingShutdown = false) | ||
{ | ||
_ = UnregisterAsync(workspace, blockingShutdown); | ||
} | ||
|
||
private async Task UnregisterAsync(Workspace workspace, bool blockingShutdown) | ||
{ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. based on previous comments, this actually feels like a bug. This code seems to be missing required try/catches, and so could tear things down if something goes wrong. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ➡️ Covered under the VSTHRD110 (fire and forget) umbrella |
||
Contract.ThrowIfFalse(workspace == _workspace); | ||
_source.Cancel(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. what happens if awaitin _analyzeTask below throws? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ➡️ Prior to this pull request, the application would crash. With this pull request, the exception will be ignored. With the changes for VSTHRD110, I am guessing we will opt for the approach of NFW. |
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3251,7 +3251,7 @@ public async Task TestAddRemoveMetadataReference_GAC() | |
|
||
[ConditionalFact(typeof(VisualStudioMSBuildInstalled))] | ||
[Trait(Traits.Feature, Traits.Features.MSBuildWorkspace)] | ||
public async void TestAddRemoveMetadataReference_ReferenceAssembly() | ||
public async Task TestAddRemoveMetadataReference_ReferenceAssembly() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. good catch! I missed that one. |
||
{ | ||
CreateFiles(GetMultiProjectSolutionFiles() | ||
.WithFile(@"CSharpProject\CSharpProject.csproj", Resources.ProjectFiles.CSharp.WithSystemNumerics)); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
out of curiosity... why? This does seem like an appropriate use of async-void. No callers use or should use the return value here. And thsi function takes care of actually ensuring that the async-mechanism it is bridging to is handled.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
➡️ Two reasons:
async void
is forbidden as more problematic than the benefits it is capable of providingThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That was intentional. The caller was not support to be aware it was async. That's because it passed in a callback object, and it was hte responsibility of the called method to invoke the callback to support the external async pattern.
I strongly disagree with this. 'async void' perfectly explains what is going on here. Furthermore, it acts as one of the best ways to mark a method as needing special handling. It would be far too easy to accidentally refactor things here and lead to a situation where cancellation or other exceptions was not handled properly. 'async void' has always been a great way for us to mark the boundary between '.net async' and other parts of our system that don't support that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
➡️ This is now covered under the VSTHRD002 umbrella. Once enabled, we will have much better analyzer enforcement for the correct implementation of fire-and-forget operations than we do today, and a key part of this enforcement effort is blocking the use of
async void
. The special case is not needed, and works against the goals of consistent, and in this case enforceable, practices.I understand that 'async void' may play an important goal in other projects, but in Roslyn it was exceedingly rare and did not have any particular meaning that needed to be preserved (due to replacement by analyzers). The easiest way to achieve consistency and clarity for average developers was eliminating the few cases where it was used.
I do not plan to reconsider this change for this pull request, but if you believe that it should be changed back we can open a new discussion (in a separate issue) to define a new set of consistency practices along with analyzer-enforced correctness as a proposed alternative to the direction seen here.