Skip to content
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

Add support for async lightbulb model. #53117

Merged
merged 68 commits into from
Jun 29, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
68 commits
Select commit Hold shift + click to select a range
bd67d0b
Initial stubs for async lightbulbs
CyrusNajmabadi May 3, 2021
25b6bba
Add parameter
CyrusNajmabadi May 3, 2021
5e4b103
Thread through priority information
CyrusNajmabadi May 3, 2021
b5ad99f
Thread through value.
CyrusNajmabadi May 3, 2021
60b9671
Fallout
CyrusNajmabadi May 3, 2021
183333d
Add docs
CyrusNajmabadi May 3, 2021
4d32a88
Add flag
CyrusNajmabadi May 3, 2021
e1b9a30
warning
CyrusNajmabadi May 4, 2021
1122406
Simplify logic
CyrusNajmabadi May 4, 2021
df499e8
use a different code
CyrusNajmabadi May 4, 2021
187ae22
Move down into the executor
CyrusNajmabadi May 4, 2021
a0e9b9f
Run high and low priority each after the other.
CyrusNajmabadi May 4, 2021
6003f2c
move down
CyrusNajmabadi May 4, 2021
ed9bf08
Push down
CyrusNajmabadi May 4, 2021
8477a12
temp
CyrusNajmabadi May 5, 2021
cb1a318
Simplify suggested action computation.
CyrusNajmabadi May 5, 2021
a2ba308
Simplify
CyrusNajmabadi May 5, 2021
34642f4
PRoduce results as soon as we have them
CyrusNajmabadi May 5, 2021
c0b4244
Switch to valuetask
CyrusNajmabadi May 5, 2021
b4834c9
fallout
CyrusNajmabadi May 5, 2021
ea93f62
restore
CyrusNajmabadi May 5, 2021
79765d6
Remove
CyrusNajmabadi May 5, 2021
f95e48b
Merge remote-tracking branch 'upstream/main-vs-deps' into asyncLightbulb
CyrusNajmabadi May 6, 2021
57765be
Merge branch 'main-vs-deps' into asyncLightbulb
CyrusNajmabadi May 6, 2021
56d51e0
Roll back to the previous model
CyrusNajmabadi May 6, 2021
89f3187
Merge remote-tracking branch 'upstream/main-vs-deps' into asyncLightbulb
CyrusNajmabadi May 7, 2021
c10ab09
Merge remote-tracking branch 'upstream/main-vs-deps' into asyncLightbulb
CyrusNajmabadi May 10, 2021
4b735b5
Update version
CyrusNajmabadi May 10, 2021
ad1c39a
Merge remote-tracking branch 'upstream/main' into asyncLightbulb
CyrusNajmabadi May 12, 2021
5651d97
Merge remote-tracking branch 'upstream/main-vs-deps' into asyncLightbulb
CyrusNajmabadi May 12, 2021
397154a
Merge remote-tracking branch 'upstream/main-vs-deps' into asyncLightbulb
CyrusNajmabadi May 13, 2021
505c91f
Update version
CyrusNajmabadi May 13, 2021
27a15e6
Update version
CyrusNajmabadi May 13, 2021
0825ee7
Merge remote-tracking branch 'upstream/main-vs-deps' into asyncLightbulb
CyrusNajmabadi May 25, 2021
6403b5e
Update version
CyrusNajmabadi May 25, 2021
3f5d239
Fix
CyrusNajmabadi May 26, 2021
5ff2685
Move to an enum
CyrusNajmabadi May 26, 2021
188be8f
Add docs
CyrusNajmabadi May 26, 2021
4aa0237
Move new code into new files
CyrusNajmabadi May 26, 2021
677099f
Wrap
CyrusNajmabadi May 26, 2021
1d8249a
REvert
CyrusNajmabadi May 26, 2021
6475254
Make sync
CyrusNajmabadi May 26, 2021
dd8e145
Fix
CyrusNajmabadi May 26, 2021
63320d4
Revert
CyrusNajmabadi May 26, 2021
726bec2
Merge remote-tracking branch 'upstream/main-vs-deps' into asyncLightbulb
CyrusNajmabadi May 26, 2021
3062206
No alloc
CyrusNajmabadi May 26, 2021
00ea3f0
Simplify
CyrusNajmabadi May 26, 2021
4e3524b
Update src/Features/Core/Portable/AddImport/AbstractAddImportCodeFixP…
CyrusNajmabadi May 26, 2021
fe96d77
Update src/Workspaces/Core/Portable/CodeActions/CodeActionPriority.cs
CyrusNajmabadi May 26, 2021
3423ad9
Update src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionSource_…
CyrusNajmabadi May 26, 2021
8ab7971
Update src/EditorFeatures/Core.Wpf/Suggestions/SuggestedActionSource_…
CyrusNajmabadi May 26, 2021
c2b1f61
Simplify
CyrusNajmabadi May 27, 2021
ddcf0b0
Simplify
CyrusNajmabadi May 27, 2021
cb1d5bd
Merge branch 'asyncLightbulb' of https://github.com/CyrusNajmabadi/ro…
CyrusNajmabadi May 27, 2021
1d59ca0
Simplify
CyrusNajmabadi May 27, 2021
8a7679f
Simplify
CyrusNajmabadi May 27, 2021
e626d4b
Rename type
CyrusNajmabadi May 27, 2021
e0ca75c
Move away from a bool
CyrusNajmabadi May 27, 2021
c81e9d6
Merge remote-tracking branch 'upstream/main-vs-deps' into asyncLightbulb
CyrusNajmabadi May 31, 2021
adfeb29
SImplify
CyrusNajmabadi May 31, 2021
2afda3c
Comments
CyrusNajmabadi May 31, 2021
249c808
Merge remote-tracking branch 'upstream/main-vs-deps' into asyncLightbulb
CyrusNajmabadi Jun 9, 2021
58df3bc
Merge remote-tracking branch 'upstream/main-vs-deps' into asyncLightbulb
CyrusNajmabadi Jun 23, 2021
7011bab
Merge remote-tracking branch 'upstream/main-vs-deps' into asyncLightbulb
CyrusNajmabadi Jun 28, 2021
ffe832e
Add option
CyrusNajmabadi Jun 28, 2021
75b96cb
Update version
CyrusNajmabadi Jun 28, 2021
d3a74c3
Rename string
CyrusNajmabadi Jun 28, 2021
b7359c6
Merge remote-tracking branch 'upstream/main-vs-deps' into asyncLightbulb
CyrusNajmabadi Jun 29, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion eng/Versions.props
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
<MicrosoftCodeAnalysisTestingVersion>1.1.0-beta1.21322.2</MicrosoftCodeAnalysisTestingVersion>
<CodeStyleAnalyzerVersion>3.10.0</CodeStyleAnalyzerVersion>
<VisualStudioEditorPackagesVersion>16.10.230</VisualStudioEditorPackagesVersion>
<VisualStudioEditorNewPackagesVersion>17.0.65-g6c25c21ba5</VisualStudioEditorNewPackagesVersion>
<VisualStudioEditorNewPackagesVersion>17.0.83-preview</VisualStudioEditorNewPackagesVersion>
<ILAsmPackageVersion>5.0.0-alpha1.19409.1</ILAsmPackageVersion>
<ILDAsmPackageVersion>5.0.0-preview.1.20112.8</ILDAsmPackageVersion>
<MicrosoftVisualStudioLanguageServerProtocolPackagesVersion>17.0.20-g6553c6c46e</MicrosoftVisualStudioLanguageServerProtocolPackagesVersion>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.

using System.Collections.Immutable;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.Diagnostics;

namespace Microsoft.CodeAnalysis.CodeStyle
Expand Down Expand Up @@ -44,6 +45,7 @@ protected AbstractBuiltInCodeStyleDiagnosticAnalyzer(ImmutableArray<DiagnosticDe
_localizableMessageFormat = Descriptor.MessageFormat;
}

public CodeActionRequestPriority RequestPriority => CodeActionRequestPriority.Normal;
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; }

protected static DiagnosticDescriptor CreateDescriptorWithId(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#nullable disable

using System.Collections.Immutable;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CodeStyle;
using Microsoft.CodeAnalysis.Diagnostics;

Expand All @@ -28,6 +29,7 @@ protected AbstractCodeQualityDiagnosticAnalyzer(
_generatedCodeAnalysisFlags = generatedCodeAnalysisFlags;
}

public CodeActionRequestPriority RequestPriority => CodeActionRequestPriority.Normal;
public sealed override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; }

public sealed override void Initialize(AnalysisContext context)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;
using Microsoft.CodeAnalysis.CodeActions;

#if CODE_STYLE
using OptionSet = Microsoft.CodeAnalysis.Diagnostics.AnalyzerConfigOptions;
Expand Down Expand Up @@ -117,6 +118,7 @@ public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics
}
}

public CodeActionRequestPriority RequestPriority => CodeActionRequestPriority.Normal;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not to get into a bikeshedding argument here, but whats the thinking around whether there are high or normal? For example "Remove unused usings" only triggers from one spot in a document so would seem to me to be a decent candidate for high priority.

Perhaps its worth documenting some guidelines on the enum (if they're not already there.. haven't got that far yet)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Effectively, everything that previously produced a 'high pri code action' is in the 'high pri request' category. Anything that produces a normal/low pri code action is in the normal request category. I didn't want to change anything in that regard here. Right now we've had a long historical precedent of recognizing two code actions (one analzyer, one refactoring) that are so important that they should beat out everything else. This PR codifies things so that not only do those come first, they are computed first so we can display them asap for the user.

public bool OpenFileOnly(OptionSet options) => false;

public override void Initialize(AnalysisContext context)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Microsoft.CodeAnalysis.Diagnostics;
Expand Down Expand Up @@ -184,6 +185,8 @@ private static void AccessSupportedDiagnostics(DiagnosticAnalyzer analyzer)

private class ThrowingDoNotCatchDiagnosticAnalyzer<TLanguageKindEnum> : ThrowingDiagnosticAnalyzer<TLanguageKindEnum>, IBuiltInAnalyzer where TLanguageKindEnum : struct
{
public CodeActionRequestPriority RequestPriority => CodeActionRequestPriority.Normal;

public bool OpenFileOnly(OptionSet options) => false;

public DiagnosticAnalyzerCategory GetAnalyzerCategory()
Expand Down
135 changes: 135 additions & 0 deletions src/EditorFeatures/Core.Wpf/Suggestions/AsyncSuggestedActionsSource.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.Editor.Shared;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Internal.Log;
using Microsoft.CodeAnalysis.Text;
using Microsoft.CodeAnalysis.UnifiedSuggestions;
using Microsoft.VisualStudio.Language.Intellisense;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Editor;
using Roslyn.Utilities;

namespace Microsoft.CodeAnalysis.Editor.Implementation.Suggestions
{
internal partial class SuggestedActionsSourceProvider
{
private partial class AsyncSuggestedActionsSource : SuggestedActionsSource, ISuggestedActionsSourceExperimental
{
public AsyncSuggestedActionsSource(
IThreadingContext threadingContext,
SuggestedActionsSourceProvider owner,
ITextView textView,
ITextBuffer textBuffer,
ISuggestedActionCategoryRegistryService suggestedActionCategoryRegistry)
: base(threadingContext, owner, textView, textBuffer, suggestedActionCategoryRegistry)
{
}

public async IAsyncEnumerable<SuggestedActionSet> GetSuggestedActionsAsync(
ISuggestedActionCategorySet requestedActionCategories,
SnapshotSpan range,
[EnumeratorCancellation] CancellationToken cancellationToken)
{
AssertIsForeground();

using var state = SourceState.TryAddReference();
if (state is null)
yield break;

var workspace = state.Target.Workspace;
if (workspace is null)
yield break;

var selection = TryGetCodeRefactoringSelection(state, range);
await workspace.Services.GetRequiredService<IWorkspaceStatusService>().WaitUntilFullyLoadedAsync(cancellationToken).ConfigureAwait(false);

using (Logger.LogBlock(FunctionId.SuggestedActions_GetSuggestedActionsAsync, cancellationToken))
{
var document = range.Snapshot.GetOpenDocumentInCurrentContextWithChanges();
if (document is null)
yield break;

// Compute and return the high pri set of fixes and refactorings first so the user
// can act on them immediately without waiting on the regular set.
var highPriSet = GetCodeFixesAndRefactoringsAsync(
state, requestedActionCategories, document, range, selection, _ => null,
CodeActionRequestPriority.High, cancellationToken).WithCancellation(cancellationToken).ConfigureAwait(false);
await foreach (var set in highPriSet)
yield return set;

var lowPriSet = GetCodeFixesAndRefactoringsAsync(
state, requestedActionCategories, document, range, selection, _ => null,
CodeActionRequestPriority.Normal, cancellationToken).WithCancellation(cancellationToken).ConfigureAwait(false);
await foreach (var set in lowPriSet)
yield return set;
}
}

private async IAsyncEnumerable<SuggestedActionSet> GetCodeFixesAndRefactoringsAsync(
ReferenceCountedDisposable<State> state,
ISuggestedActionCategorySet requestedActionCategories,
Document document,
SnapshotSpan range,
TextSpan? selection,
Func<string, IDisposable?> addOperationScope,
CodeActionRequestPriority priority,
[EnumeratorCancellation] CancellationToken cancellationToken)
{
var workspace = document.Project.Solution.Workspace;
var supportsFeatureService = workspace.Services.GetRequiredService<ITextBufferSupportsFeatureService>();

var fixesTask = GetCodeFixesAsync(
state, supportsFeatureService, requestedActionCategories, workspace, document, range,
addOperationScope, priority, isBlocking: false, cancellationToken);
var refactoringsTask = GetRefactoringsAsync(
state, supportsFeatureService, requestedActionCategories, workspace, document, selection,
addOperationScope, priority, isBlocking: false, cancellationToken);

if (priority == CodeActionRequestPriority.High)
{
// in a high pri scenario, return data as soon as possible so that the user can interact with them.
// this is especially important for state-machine oriented refactorings (like rename) where the user
// should always have access to them effectively synchronously.
var firstTask = await Task.WhenAny(fixesTask, refactoringsTask).ConfigureAwait(false);
var secondTask = firstTask == fixesTask ? refactoringsTask : fixesTask;

var orderedTasks = new[] { firstTask, secondTask };
foreach (var task in orderedTasks)
{
if (task == fixesTask)
{
var fixes = await fixesTask.ConfigureAwait(false);
foreach (var set in ConvertToSuggestedActionSets(state, selection, fixes, ImmutableArray<UnifiedSuggestedActionSet>.Empty))
yield return set;
}
else
{
Contract.ThrowIfFalse(task == refactoringsTask);

var refactorings = await refactoringsTask.ConfigureAwait(false);
foreach (var set in ConvertToSuggestedActionSets(state, selection, ImmutableArray<UnifiedSuggestedActionSet>.Empty, refactorings))
yield return set;
}
}
}
else
{
var actionsArray = await Task.WhenAll(fixesTask, refactoringsTask).ConfigureAwait(false);
foreach (var set in ConvertToSuggestedActionSets(state, selection, fixes: actionsArray[0], refactorings: actionsArray[1]))
yield return set;
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ internal partial class SuggestedActionsSourceProvider
{
private partial class SuggestedActionsSource
{
private sealed class State : IDisposable
protected sealed class State : IDisposable
{
private readonly SuggestedActionsSource _source;

Expand Down
Loading