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

Semantic snippets: handle case with inline statement snippets before member access expression #74966

Merged
merged 2 commits into from
Sep 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
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.LanguageService;
Expand Down Expand Up @@ -38,6 +39,9 @@ internal abstract class AbstractCSharpForLoopSnippetProvider : AbstractForLoopSn

protected abstract void AddSpecificPlaceholders(MultiDictionary<string, int> placeholderBuilder, ExpressionSyntax initializer, ExpressionSyntax rightOfCondition);

protected override bool CanInsertStatementAfterToken(SyntaxToken token)
=> token.IsBeginningOfStatementContext() || token.IsBeginningOfGlobalStatementContext();

protected override ForStatementSyntax GenerateStatement(SyntaxGenerator generator, SyntaxContext syntaxContext, InlineExpressionInfo? inlineExpressionInfo)
{
var semanticModel = syntaxContext.SemanticModel;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.Composition;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CSharp.Extensions.ContextQuery;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Editing;
using Microsoft.CodeAnalysis.Host.Mef;
Expand All @@ -26,6 +27,9 @@ internal sealed class CSharpDoWhileLoopSnippetProvider()

public override string Description => CSharpFeaturesResources.do_while_loop;

protected override bool CanInsertStatementAfterToken(SyntaxToken token)
=> token.IsBeginningOfStatementContext() || token.IsBeginningOfGlobalStatementContext();

protected override DoStatementSyntax GenerateStatement(SyntaxGenerator generator, SyntaxContext syntaxContext, InlineExpressionInfo? inlineExpressionInfo)
{
return SyntaxFactory.DoStatement(
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.CSharp.Extensions.ContextQuery;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Editing;
using Microsoft.CodeAnalysis.Host.Mef;
Expand Down Expand Up @@ -51,6 +52,9 @@ protected override bool IsValidSnippetLocationCore(SnippetContext context, Cance
return base.IsValidSnippetLocationCore(context, cancellationToken);
}

protected override bool CanInsertStatementAfterToken(SyntaxToken token)
=> token.IsBeginningOfStatementContext() || token.IsBeginningOfGlobalStatementContext();

protected override ForEachStatementSyntax GenerateStatement(SyntaxGenerator generator, SyntaxContext syntaxContext, InlineExpressionInfo? inlineExpressionInfo)
{
var semanticModel = syntaxContext.SemanticModel;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.Composition;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CSharp.Extensions.ContextQuery;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.Snippets;
Expand All @@ -23,6 +24,9 @@ internal sealed class CSharpIfSnippetProvider() : AbstractIfSnippetProvider<IfSt

public override string Description => FeaturesResources.if_statement;

protected override bool CanInsertStatementAfterToken(SyntaxToken token)
=> token.IsBeginningOfStatementContext() || token.IsBeginningOfGlobalStatementContext();

protected override ExpressionSyntax GetCondition(IfStatementSyntax node)
=> node.Condition;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.Composition;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CSharp.Extensions.ContextQuery;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.Snippets;
Expand All @@ -23,6 +24,9 @@ internal sealed class CSharpWhileLoopSnippetProvider() : AbstractWhileLoopSnippe

public override string Description => FeaturesResources.while_loop;

protected override bool CanInsertStatementAfterToken(SyntaxToken token)
=> token.IsBeginningOfStatementContext() || token.IsBeginningOfGlobalStatementContext();

protected override ExpressionSyntax GetCondition(WhileStatementSyntax node)
=> node.Condition;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -539,6 +539,65 @@ void M(bool flag)
""");
}

[Fact]
public async Task InsertInlineSnippetWhenDottingBeforeMemberAccessExpressionOnTheNextLineTest()
{
await VerifySnippetAsync("""
using System;

class C
{
void M(bool flag)
{
flag.$$
Console.WriteLine();
}
}
""", $$"""
using System;

class C
{
void M(bool flag)
{
{{SnippetIdentifier}} (flag)
{
$$
}
Console.WriteLine();
}
}
""");
}

[Fact]
public async Task NoInlineSnippetWhenDottingBeforeMemberAccessExpressionOnTheSameLineTest()
{
await VerifySnippetIsAbsentAsync("""
class C
{
void M(bool flag)
{
flag.$$ToString();
}
}
""");
}

[Fact]
public async Task NoInlineSnippetWhenDottingBeforeContextualKeywordOnTheSameLineTest()
{
await VerifySnippetIsAbsentAsync("""
class C
{
void M(bool flag)
{
flag.$$var a = 0;
}
}
""");
}

[Fact]
public async Task NoInlineSnippetForTypeItselfTest()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -555,6 +555,66 @@ void M(bool flag)
""");
}

[Fact]
public async Task InsertInlineDoSnippetWhenDottingBeforeMemberAccessExpressionOnTheNextLineTest()
{
await VerifySnippetAsync("""
using System;

class C
{
void M(bool flag)
{
flag.$$
Console.WriteLine();
}
}
""", """
using System;

class C
{
void M(bool flag)
{
do
{
$$
}
while (flag);
Console.WriteLine();
}
}
""");
}

[Fact]
public async Task NoInlineDoSnippetWhenDottingBeforeMemberAccessExpressionOnTheSameLineTest()
{
await VerifySnippetIsAbsentAsync("""
class C
{
void M(bool flag)
{
flag.$$ToString();
}
}
""");
}

[Fact]
public async Task NoInlineDoSnippetWhenDottingBeforeContextualKeywordOnTheSameLineTest()
{
await VerifySnippetIsAbsentAsync("""
class C
{
void M(bool flag)
{
flag.$$var a = 0;
}
}
""");
}

[Fact]
public async Task NoInlineDoSnippetForTypeItselfTest()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -598,6 +598,69 @@ void M(IEnumerable<int> ints)
""");
}

[Fact]
public async Task InsertInlineForEachSnippetWhenDottingBeforeMemberAccessExpressionOnTheNextLineTest()
{
await VerifySnippetAsync("""
using System;

class C
{
void M(int[] ints)
{
ints.$$
Console.WriteLine();
}
}
""", """
using System;

class C
{
void M(int[] ints)
{
foreach (var {|0:item|} in ints)
{
$$
}
Console.WriteLine();
}
}
""");
}

[Fact]
public async Task NoInlineForEachSnippetWhenDottingBeforeMemberAccessExpressionOnTheSameLineTest()
{
await VerifySnippetIsAbsentAsync("""
using System;

class C
{
void M(int[] ints)
{
ints.$$ToString();
}
}
""");
}

[Fact]
public async Task NoInlineForEachSnippetWhenDottingBeforeContextualKeywordOnTheSameLineTest()
{
await VerifySnippetIsAbsentAsync("""
using System;

class C
{
void M(int[] ints)
{
ints.$$var a = 0;
}
}
""");
}

[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/69598")]
public async Task InsertInlineAwaitForEachSnippetWhenDottingBeforeContextualKeywordTest1()
{
Expand Down Expand Up @@ -701,6 +764,74 @@ void M(IAsyncEnumerable<int> asyncInts)
referenceAssemblies: ReferenceAssemblies.Net.Net70);
}

[Fact]
public async Task InsertInlineAwaitForEachSnippetWhenDottingBeforeMemberAccessExpressionOnTheNextLineTest()
{
await VerifySnippetAsync("""
using System;
using System.Collections.Generic;

class C
{
void M(IAsyncEnumerable<int> ints)
{
ints.$$
Console.WriteLine();
}
}
""", """
using System;
using System.Collections.Generic;

class C
{
void M(IAsyncEnumerable<int> ints)
{
await foreach (var {|0:item|} in ints)
{
$$
}
Console.WriteLine();
}
}
""",
referenceAssemblies: ReferenceAssemblies.Net.Net80);
}

[Fact]
public async Task NoInlineAwaitForEachSnippetWhenDottingBeforeMemberAccessExpressionOnTheSameLineTest()
{
await VerifySnippetIsAbsentAsync("""
using System.Collections.Generic;

class C
{
void M(IAsyncEnumerable<int> ints)
{
ints.$$ToString();
}
}
""",
referenceAssemblies: ReferenceAssemblies.Net.Net80);
}

[Fact]
public async Task NoInlineAwaitForEachSnippetWhenDottingBeforeContextualKeywordOnTheSameLineTest()
{
await VerifySnippetIsAbsentAsync("""
using System.Collections.Generic;

class C
{
void M(IAsyncEnumerable<int> ints)
{
ints.$$var a = 0;
}
}
""",
referenceAssemblies: ReferenceAssemblies.Net.Net80);
}

[Theory]
[MemberData(nameof(CommonSnippetTestData.CommonEnumerableTypes), MemberType = typeof(CommonSnippetTestData))]
public async Task NoInlineForEachSnippetForTypeItselfTest(string collectionType)
Expand Down
Loading
Loading