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 async modifier on await completion #48352

Merged
merged 45 commits into from
Jul 16, 2021

Conversation

Youssef1313
Copy link
Member

@Youssef1313 Youssef1313 commented Oct 6, 2020

Fixes #45368

![await](https://user-images.githubusercontent.com/31348972/110206522-e2c1c800-7e86-11eb-8827-7bda1c4edcdf.gif) (Outdated)

await

TODO:

  • Make sure this doesn't cause problems with top-level statements.

@Youssef1313 Youssef1313 force-pushed the await-completion branch 4 times, most recently from 65354d1 to d60bef3 Compare October 6, 2020 01:22
@Youssef1313 Youssef1313 marked this pull request as ready for review October 7, 2020 13:25
@Youssef1313 Youssef1313 requested a review from a team as a code owner October 7, 2020 13:25
@jinujoseph jinujoseph added Area-IDE Community The pull request was submitted by a contributor who is not a Microsoft employee. labels Oct 8, 2020
@Youssef1313
Copy link
Member Author

Pinging @genlu for review.

var method = syntaxContext.TargetToken.GetAncestor(node => node.IsAsyncSupportingFunctionSyntax());
if (method is not null && !method.GetModifiers().Any(SyntaxKind.AsyncKeyword))
{
context.AddItem(CommonCompletionItem.Create("await", string.Empty, CompletionItemRules.Default, inlineDescription: "Make container async"));
Copy link
Member

Choose a reason for hiding this comment

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

This might end up conflicting with the item provided by keyword recommender, and one would get deduplicated: since they have seem to have identical full display text (prefix + text + suffix), this will be decided by the order of providers being called.

See:
http://sourceroslyn.io/#Microsoft.CodeAnalysis.Features/Completion/CompletionServiceWithProviders.cs,484

Copy link
Member

Choose a reason for hiding this comment

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

Hiding the keyword might be the behavior we want, if so, we should figure out a way to make it explicit.
Otherwise, we need to show them both and give one higher priority . Before we get to the detail on how to implement this, let's figure out which approach we'd like to take.


In reply to: 517718403 [](ancestors = 517718403)

Copy link
Member

@genlu genlu Mar 19, 2021

Choose a reason for hiding this comment

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

I don't think we have reached a conclusion on this yet. Current behavior relies on the implementation detail of completion service which is fragile. One way to resolve the interaction issue between two providers that provide "await" item is to fold the keyword provider into this one.

@CyrusNajmabadi thoughts?


namespace Microsoft.CodeAnalysis.CSharp.Completion.Providers
{
[ExportCompletionProvider(nameof(AwaitCompletionProvider), LanguageNames.CSharp)]
Copy link
Member

Choose a reason for hiding this comment

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

I think this would be valuable in VB too. Any plan to add VB support in this PR?

Copy link
Member Author

Choose a reason for hiding this comment

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

@genlu I'll work on supporting VB.

Copy link
Member

Choose a reason for hiding this comment

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

👍 would def want VB here.

Copy link
Member

Choose a reason for hiding this comment

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

Are you planning to add VB support in this PR?

Copy link
Member

Choose a reason for hiding this comment

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

question still remains. but i'm ok with no vb support initially if you'd prefer to punt on that for now.

Copy link
Member Author

Choose a reason for hiding this comment

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

@CyrusNajmabadi I'll likely do that in a separate PR :(

{
}

internal override ImmutableHashSet<char> TriggerCharacters => CompletionUtilities.CommonTriggerCharactersWithArgumentList;
Copy link
Member

Choose a reason for hiding this comment

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

@dibarbet @allisonchou is this the proper TriggerCharacters to use?

Copy link
Member Author

Choose a reason for hiding this comment

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


// MethodDeclarationSyntax, LocalFunctionStatementSyntax, AnonymousMethodExpressionSyntax, ParenthesizedLambdaExpressionSyntax, SimpleLambdaExpressionSyntax.

var newDeclaration = AddAsyncModifier(declaration, SyntaxGenerator.GetGenerator(document));
Copy link
Member

Choose a reason for hiding this comment

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

Does this work in debugging scenarios? e.g. EnC, watch window, etc

Copy link
Member Author

Choose a reason for hiding this comment

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

@genlu I'm not sure.

@genlu
Copy link
Member

genlu commented Nov 5, 2020

FYI @JoeRobich @333fred This is a new completion provider that make changes outside of current span, I guess it might need some additional work in OmniSharp to enable it in VS Code?

@genlu
Copy link
Member

genlu commented Nov 5, 2020

Could you please added some tests as well? Thanks!

genlu
genlu previously requested changes Nov 5, 2020
Copy link
Member

@genlu genlu left a comment

Choose a reason for hiding this comment

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

Done with pass. Thanks for the contribution :)
In general, I like the approach of creating a separate provider. One of the major question I have is about dealing with item of await keyword and item from this provider. @CyrusNajmabadi have you discussed this with @Youssef1313 already?

@genlu
Copy link
Member

genlu commented Jan 5, 2021

Hi @Youssef1313, any update on this PR? Please let me know if there's anything I can do to help moving this forward. Thanks! :)

@Youssef1313
Copy link
Member Author

Hi @Youssef1313, any update on this PR? Please let me know if there's anything I can do to help moving this forward. Thanks! :)

@genlu Thanks for pinging. I might take some time to be able to work on this again. I'm okay if you (or any other external contributor) would like to take this over and continue the work.

Base automatically changed from master to main March 3, 2021 23:52
@Youssef1313
Copy link
Member Author

Ping @CyrusNajmabadi


return;

static CompletionItem GetCompletionItem(bool shouldMakeContainerAsync)
Copy link
Member

Choose a reason for hiding this comment

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

this helper method seems pointless. inline?

var documentWithAsyncModifier = document.WithSyntaxRoot(root.ReplaceNode(declaration, AddAsyncModifier(declaration)));
using var _ = ArrayBuilder<TextChange>.GetInstance(out var builder);

builder.AddRange(await documentWithAsyncModifier.GetTextChangesAsync(document, cancellationToken).ConfigureAwait(false));
Copy link
Member

Choose a reason for hiding this comment

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

this part is actually a bit terrifying. tehre is no invariant that GetTextChanges returns good edits. Instead of going this route, i would instead either:

  1. just literally hardcode in the logic for determining the span where async should go.
  2. use AddAsyncModifier, then directly check the new declaration for the async token and figure out the span from taht

Either of those will give a nice narrow text edit that we can depend on.

This is a blocker for this PR currently.

Copy link
Member Author

Choose a reason for hiding this comment

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

Note: This was following what's currently done in another completion provider:

var importChanges = await formattedDocumentWithImport.GetTextChangesAsync(document, cancellationToken).ConfigureAwait(false);

I'll try with either of the approaches you mentioned.

tehre is no invariant that GetTextChanges returns good edits

I'm curious what "good edits" mean?

Copy link
Member

Choose a reason for hiding this comment

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

I'm curious what "good edits" mean?

So if you added async , you'd ideally get an edit like 'async ' was added at position 15. But there's no guarantee of that. it might literally say: i added the entire contents of the file at position 0.

return CompletionChange.Create(CodeAnalysis.Completion.Utilities.Collapse(newText, builder.ToImmutableArray()));
}

private static SyntaxNode AddAsyncModifier(SyntaxNode declaration)
Copy link
Member

Choose a reason for hiding this comment

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

since we're manually adding the async modifier anyways, it's fairly trivial for us to instead just determine the text-edit for where the async modifier should go directly. please switch to that. thanks!

Copy link
Member

@CyrusNajmabadi CyrusNajmabadi left a comment

Choose a reason for hiding this comment

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

definitely some necesxsary changes to make :)

@Youssef1313
Copy link
Member Author

@CyrusNajmabadi This is ready for another look.

@Youssef1313 Youssef1313 closed this Jul 5, 2021
@Youssef1313 Youssef1313 reopened this Jul 5, 2021
@Youssef1313
Copy link
Member Author

Ping @CyrusNajmabadi

@CyrusNajmabadi
Copy link
Member

Thanks! really looking forward to this :)

@CyrusNajmabadi CyrusNajmabadi dismissed genlu’s stale review July 16, 2021 22:03

All feedback responded to.

@CyrusNajmabadi CyrusNajmabadi merged commit ad31382 into dotnet:main Jul 16, 2021
@ghost ghost added this to the Next milestone Jul 16, 2021
@Youssef1313 Youssef1313 deleted the await-completion branch July 17, 2021 05:14
@allisonchou allisonchou modified the milestones: Next, 17.0.P3 Jul 27, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-IDE Community The pull request was submitted by a contributor who is not a Microsoft employee.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Completing 'await' should automatically add 'async' if missing
6 participants