Skip to content

Commit

Permalink
Merge pull request #72477 from DoctorKrolic/no-async-console
Browse files Browse the repository at this point in the history
Semantic snippets: Do not generate async write in `cw` snippet
  • Loading branch information
sharwell authored Mar 11, 2024
2 parents 0ed61bd + ab63819 commit fc58c2a
Show file tree
Hide file tree
Showing 3 changed files with 10 additions and 48 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@
// 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.Threading.Tasks;
using Microsoft.CodeAnalysis.CSharp.Completion.CompletionProviders.Snippets;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
using Xunit;
Expand Down Expand Up @@ -46,7 +44,7 @@ public void Method()
}

[WpfFact]
public async Task InsertAsyncConsoleSnippetTest()
public async Task InsertNormalConsoleSnippetInAsyncContextTest()
{
var markupBeforeCommit =
"""
Expand All @@ -67,7 +65,7 @@ class Program
{
public async Task MethodAsync()
{
await Console.Out.WriteLineAsync($$);
Console.WriteLine($$);
}
}
""";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,40 +3,16 @@
// See the LICENSE file in the project root for more information.

using System;
using System.Collections.Immutable;
using System.Composition;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CSharp.Extensions;
using Microsoft.CodeAnalysis.CSharp.Extensions.ContextQuery;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Editing;
using Microsoft.CodeAnalysis.Formatting;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.PooledObjects;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Shared.Extensions.ContextQuery;
using Microsoft.CodeAnalysis.Simplification;
using Microsoft.CodeAnalysis.Snippets;
using Microsoft.CodeAnalysis.Snippets.SnippetProviders;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;

namespace Microsoft.CodeAnalysis.CSharp.Snippets;

[ExportSnippetProvider(nameof(ISnippetProvider), LanguageNames.CSharp), Shared]
internal sealed class CSharpConsoleSnippetProvider : AbstractConsoleSnippetProvider
[method: ImportingConstructor]
[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
internal sealed class CSharpConsoleSnippetProvider() : AbstractConsoleSnippetProvider
{
[ImportingConstructor]
[Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
public CSharpConsoleSnippetProvider()
{
}

protected override SyntaxNode? GetAsyncSupportingDeclaration(SyntaxToken token)
{
var node = token.GetAncestor(node => node.IsAsyncSupportingFunctionSyntax());
return node;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@ namespace Microsoft.CodeAnalysis.Snippets;

internal abstract class AbstractConsoleSnippetProvider : AbstractStatementSnippetProvider
{
protected abstract SyntaxNode? GetAsyncSupportingDeclaration(SyntaxToken token);

public override string Identifier => "cw";

public override string Description => FeaturesResources.console_writeline;
Expand All @@ -44,25 +42,15 @@ protected override bool IsValidSnippetLocation(in SnippetContext context, Cancel
return syntaxFacts.IsExpressionStatement;
}

protected override async Task<TextChange> GenerateSnippetTextChangeAsync(Document document, int position, CancellationToken cancellationToken)
protected override Task<TextChange> GenerateSnippetTextChangeAsync(Document document, int position, CancellationToken cancellationToken)
{
var generator = SyntaxGenerator.GetGenerator(document);
var tree = await document.GetRequiredSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);
var token = tree.FindTokenOnLeftOfPosition(position, cancellationToken);

// We know symbol is not null at this point since it was checked when determining
// if we are in a valid location to insert the snippet.
var declaration = GetAsyncSupportingDeclaration(token);
var isAsync = declaration is not null && generator.GetModifiers(declaration).IsAsync;

var invocation = isAsync
? generator.AwaitExpression(generator.InvocationExpression(
generator.MemberAccessExpression(generator.MemberAccessExpression(generator.IdentifierName(nameof(Console)), generator.IdentifierName(nameof(Console.Out))), nameof(Console.Out.WriteLineAsync))))
: generator.InvocationExpression(generator.MemberAccessExpression(generator.IdentifierName(nameof(Console)), nameof(Console.WriteLine)));

var invocation = generator.InvocationExpression(generator.MemberAccessExpression(generator.IdentifierName(nameof(Console)), nameof(Console.WriteLine)));
var expressionStatement = generator.ExpressionStatement(invocation);

// Need to normalize the whitespace for the asynchronous case because it doesn't insert a space following the await
return new TextChange(TextSpan.FromBounds(position, position), expressionStatement.NormalizeWhitespace().ToFullString());
var change = new TextChange(TextSpan.FromBounds(position, position), expressionStatement.ToFullString());
return Task.FromResult(change);
}

/// <summary>
Expand Down

0 comments on commit fc58c2a

Please sign in to comment.