Skip to content

Commit

Permalink
Semantic snippets: handle case with inline statement snippets before …
Browse files Browse the repository at this point in the history
…member access expression (#74966)

* Rework how inline statement snippets determine if they are valid on a position to handle member access expression case

* Reference assemblies
  • Loading branch information
DoctorKrolic authored Sep 11, 2024
1 parent 6de8947 commit 7b75058
Show file tree
Hide file tree
Showing 11 changed files with 434 additions and 5 deletions.
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
60 changes: 60 additions & 0 deletions src/Features/CSharpTest/Snippets/CSharpDoSnippetProviderTests.cs
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
131 changes: 131 additions & 0 deletions src/Features/CSharpTest/Snippets/CSharpForEachSnippetProviderTests.cs
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

0 comments on commit 7b75058

Please sign in to comment.