提交 5aedc276 编写于 作者: N Neme12 提交者: Julien Couvreur

Fixing 'else' keyword completion (#25703)

Merging on behalf of @Neme12. Thanks!
上级 998b5b30
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
using Xunit; using Xunit;
namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Recommendations namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Recommendations
...@@ -86,50 +87,355 @@ public async Task TestAfterHashAndSpace() ...@@ -86,50 +87,355 @@ public async Task TestAfterHashAndSpace()
} }
[Fact, Trait(Traits.Feature, Traits.Features.KeywordRecommending)] [Fact, Trait(Traits.Feature, Traits.Features.KeywordRecommending)]
public async Task TestAfterIf() public async Task TestNotAfterIf()
{ {
await VerifyKeywordAsync(AddInsideMethod( await VerifyAbsenceAsync(AddInsideMethod(
@"if (true) @"if (true)
Console.WriteLine();
$$")); $$"));
} }
[Fact, Trait(Traits.Feature, Traits.Features.KeywordRecommending)] [Theory, Trait(Traits.Feature, Traits.Features.KeywordRecommending)]
public async Task TestAfterIfBlock() [InlineData("Console.WriteLine();")]
[InlineData("{ }")]
[InlineData("while (true) { }")]
public async Task TestAfterIfStatement(string statement)
{ {
await VerifyKeywordAsync(AddInsideMethod( await VerifyKeywordAsync(AddInsideMethod(
@"if (true) $@"if (true)
{ {statement}
$$"));
}
[Theory, Trait(Traits.Feature, Traits.Features.KeywordRecommending)]
[InlineData("Console.WriteLine();")]
[InlineData("{ }")]
[InlineData("while (true) { }")]
public async Task TestAfterIfStatement_BeforeElse(string statement)
{
await VerifyKeywordAsync(AddInsideMethod(
$@"if (true)
{statement}
$$
else"));
}
[Theory, Trait(Traits.Feature, Traits.Features.KeywordRecommending)]
[InlineData("Console.WriteLine();")]
[InlineData("{ }")]
[InlineData("while (true) { }")]
public async Task TestAfterIfNestedIfStatement(string statement)
{
await VerifyKeywordAsync(AddInsideMethod(
$@"if (true)
if (true)
{statement}
$$"));
}
[Theory, Trait(Traits.Feature, Traits.Features.KeywordRecommending)]
[InlineData("Console.WriteLine();")]
[InlineData("{ }")]
[InlineData("while (true) { }")]
public async Task TestAfterIfNestedIfStatement_BeforeElse(string statement)
{
await VerifyKeywordAsync(AddInsideMethod(
$@"if (true)
if (true)
{statement}
$$
else"));
}
[WorkItem(25336, "https://github.com/dotnet/roslyn/issues/25336")]
[Theory, Trait(Traits.Feature, Traits.Features.KeywordRecommending)]
[InlineData("Console.WriteLine();")]
[InlineData("{ }")]
[InlineData("while (true) { }")]
public async Task TestAfterIfNestedIfElseStatement(string statement)
{
await VerifyKeywordAsync(AddInsideMethod(
$@"if (true)
if (true)
Console.WriteLine();
else
{statement}
$$"));
}
[WorkItem(25336, "https://github.com/dotnet/roslyn/issues/25336")]
[Theory, Trait(Traits.Feature, Traits.Features.KeywordRecommending)]
[InlineData("Console.WriteLine();")]
[InlineData("{ }")]
[InlineData("while (true) { }")]
public async Task TestAfterIfNestedIfElseStatement_BeforeElse(string statement)
{
await VerifyKeywordAsync(AddInsideMethod(
$@"if (true)
if (true)
Console.WriteLine();
else
{statement}
$$
else"));
}
[Theory, Trait(Traits.Feature, Traits.Features.KeywordRecommending)]
[InlineData("Console.WriteLine();")]
[InlineData("{ }")]
[InlineData("while (true) { }")]
public async Task TestNotAfterIfNestedIfElseElseStatement(string statement)
{
await VerifyAbsenceAsync(AddInsideMethod(
$@"if (true)
if (true)
Console.WriteLine();
else
Console.WriteLine();
else
{statement}
$$"));
}
[Theory, Trait(Traits.Feature, Traits.Features.KeywordRecommending)]
[InlineData("Console.WriteLine();")]
[InlineData("{ }")]
[InlineData("while (true) { }")]
public async Task TestNotAfterIfStatementElse(string statement)
{
await VerifyAbsenceAsync(AddInsideMethod(
$@"if (true)
{statement}
else
$$"));
}
[Theory, Trait(Traits.Feature, Traits.Features.KeywordRecommending)]
[InlineData("Console.WriteLine();")]
[InlineData("{ }")]
[InlineData("while (true) { }")]
public async Task TestNotAfterIfElseStatement(string statement)
{
await VerifyAbsenceAsync(AddInsideMethod(
$@"if (true)
Console.WriteLine(); Console.WriteLine();
} else
{statement}
$$")); $$"));
} }
[Fact, Trait(Traits.Feature, Traits.Features.KeywordRecommending)] [Theory, Trait(Traits.Feature, Traits.Features.KeywordRecommending)]
public async Task TestNotAfterElse1() [InlineData("Console.WriteLine();")]
[InlineData("{ }")]
[InlineData("while (true) { }")]
public async Task TestAfterIfElseNestedIfStatement(string statement)
{
await VerifyKeywordAsync(AddInsideMethod(
$@"if (true)
Console.WriteLine();
else
if (true)
{statement}
$$"));
}
[Theory, Trait(Traits.Feature, Traits.Features.KeywordRecommending)]
[InlineData("Console.WriteLine();")]
[InlineData("{ }")]
[InlineData("while (true) { }")]
public async Task TestAfterIfElseNestedIfStatement_BeforeElse(string statement)
{
await VerifyKeywordAsync(AddInsideMethod(
$@"if (true)
Console.WriteLine();
else
if (true)
{statement}
$$
else"));
}
[Theory, Trait(Traits.Feature, Traits.Features.KeywordRecommending)]
[InlineData("Console.WriteLine();")]
[InlineData("{ }")]
[InlineData("while (true) { }")]
public async Task TestNotAfterIfElseNestedIfElseStatement(string statement)
{ {
await VerifyAbsenceAsync(AddInsideMethod( await VerifyAbsenceAsync(AddInsideMethod(
@"if (true) $@"if (true)
Console.WriteLine(); Console.WriteLine();
else $$")); else
if (true)
Console.WriteLine();
else
{statement}
$$"));
}
[Theory, Trait(Traits.Feature, Traits.Features.KeywordRecommending)]
[InlineData("Console.WriteLine();")]
[InlineData("{ }")]
[InlineData("while (true) { }")]
public async Task TestAfterWhileIfWhileNestedIfElseStatement(string statement)
{
await VerifyKeywordAsync(AddInsideMethod(
$@"while (true)
if (true)
while (true)
if (true)
Console.WriteLine();
else
{statement}
$$"));
}
[Theory, Trait(Traits.Feature, Traits.Features.KeywordRecommending)]
[InlineData("Console.WriteLine();")]
[InlineData("{ }")]
[InlineData("while (true) { }")]
public async Task TestAfterWhileIfWhileNestedIfElseStatement_BeforeElse(string statement)
{
await VerifyKeywordAsync(AddInsideMethod(
$@"while (true)
if (true)
while (true)
if (true)
Console.WriteLine();
else
{statement}
$$
else"));
}
[Theory, Trait(Traits.Feature, Traits.Features.KeywordRecommending)]
[InlineData("Console.WriteLine();")]
[InlineData("{ }")]
[InlineData("while (true) { }")]
public async Task TestNotAfterWhileIfWhileNestedIfElseElseStatement(string statement)
{
await VerifyAbsenceAsync(AddInsideMethod(
$@"while (true)
if (true)
while (true)
if (true)
Console.WriteLine();
else
Console.WriteLine();
else
{statement}
$$"));
}
[Theory, Trait(Traits.Feature, Traits.Features.KeywordRecommending)]
[InlineData("Console")]
[InlineData("Console.")]
[InlineData("Console.WriteLine(")]
[InlineData("Console.WriteLine()")]
[InlineData("{")]
[InlineData("{ Console.WriteLine();")]
[InlineData("while")]
[InlineData("while (true)")]
[InlineData("while (true) {")]
[InlineData("while (true) { { }")]
[InlineData("for (int i = 0;")]
public async Task TestNotAfterIfIncompleteStatement(string statement)
{
await VerifyAbsenceAsync(AddInsideMethod(
$@"if (true)
{statement}
$$"));
}
[Theory, Trait(Traits.Feature, Traits.Features.KeywordRecommending)]
[InlineData("Console")]
[InlineData("Console.")]
[InlineData("Console.WriteLine(")]
[InlineData("Console.WriteLine()")]
[InlineData("{")]
[InlineData("{ Console.WriteLine();")]
[InlineData("while")]
[InlineData("while (true)")]
[InlineData("while (true) {")]
[InlineData("while (true) { { }")]
[InlineData("for (int i = 0;")]
public async Task TestNotAfterIfNestedIfIncompleteStatement(string statement)
{
await VerifyAbsenceAsync(AddInsideMethod(
$@"if (true)
if (true)
{statement}
$$"));
}
[Theory, Trait(Traits.Feature, Traits.Features.KeywordRecommending)]
[InlineData("Console")]
[InlineData("Console.")]
[InlineData("Console.WriteLine(")]
[InlineData("Console.WriteLine()")]
[InlineData("{")]
[InlineData("{ Console.WriteLine();")]
[InlineData("while")]
[InlineData("while (true)")]
[InlineData("while (true) {")]
[InlineData("while (true) { { }")]
[InlineData("for (int i = 0;")]
public async Task TestNotAfterIfNestedIfElseIncompleteStatement(string statement)
{
await VerifyAbsenceAsync(AddInsideMethod(
$@"if (true)
if (true)
Console.WriteLine();
else
{statement}
$$"));
}
[Theory, Trait(Traits.Feature, Traits.Features.KeywordRecommending)]
[InlineData("Console.WriteLine();")]
[InlineData("{ }")]
[InlineData("while (true) { }")]
public async Task TestAfterIfNestedIfIncompleteStatementElseStatement(string statement)
{
await VerifyKeywordAsync(AddInsideMethod(
$@"if (true)
if (true)
Console // Incomplete, but that's fine. This is not the if statement we care about.
else
{statement}
$$"));
}
[Theory, Trait(Traits.Feature, Traits.Features.KeywordRecommending)]
[InlineData("Console.WriteLine();")]
[InlineData("{ }")]
[InlineData("while (true) { }")]
public async Task TestAfterIfNestedIfIncompleteStatementElseStatement_BeforeElse(string statement)
{
await VerifyKeywordAsync(AddInsideMethod(
$@"if (true)
if (true)
Console // Incomplete, but that's fine. This is not the if statement we care about.
else
{statement}
$$
else"));
} }
[Fact, Trait(Traits.Feature, Traits.Features.KeywordRecommending)] [Fact, Trait(Traits.Feature, Traits.Features.KeywordRecommending)]
public async Task TestNotAfterElse2() public async Task TestNotInsideStatement()
{ {
await VerifyAbsenceAsync(AddInsideMethod( await VerifyAbsenceAsync(AddInsideMethod(
@"if (true) @"if (true)
{ Console.WriteLine()$$; // Complete statement, but we're not at the end of it.
Console.WriteLine(); "));
}
else $$"));
} }
[Fact, Trait(Traits.Feature, Traits.Features.KeywordRecommending)] [Fact, Trait(Traits.Feature, Traits.Features.KeywordRecommending)]
public async Task TestNotAfterMemberAccess() public async Task TestNotAfterSkippedToken()
{ {
await VerifyAbsenceAsync(AddInsideMethod( await VerifyAbsenceAsync(AddInsideMethod(
@"if (true)string.$$")); @"if (true)
Console.WriteLine();,
$$"));
} }
} }
} }
...@@ -23,35 +23,23 @@ protected override bool IsValidContext(int position, CSharpSyntaxContext context ...@@ -23,35 +23,23 @@ protected override bool IsValidContext(int position, CSharpSyntaxContext context
var token = context.TargetToken; var token = context.TargetToken;
var statement = token.GetAncestor<StatementSyntax>(); // We have to consider all ancestor if statements of the last token until we find a match for this 'else':
var ifStatement = statement.GetAncestorOrThis<IfStatementSyntax>(); // while (true)
// if (true)
if (statement == null || ifStatement == null) // while (true)
// if (true)
// Console.WriteLine();
// else
// Console.WriteLine();
// $$
foreach (var ifStatement in token.GetAncestors<IfStatementSyntax>())
{ {
return false; // If there's a missing token at the end of the statement, it's incomplete and we do not offer 'else'.
} // context.TargetToken does not include zero width so in that case these will never be equal.
if (ifStatement.Statement.GetLastToken(includeZeroWidth: true) == token)
// cases: {
// if (goo) return true;
// Console.WriteLine(); }
// |
// if (goo)
// Console.WriteLine();
// e|
if (token.IsKind(SyntaxKind.SemicolonToken) && ifStatement.Statement.GetLastToken(includeSkipped: true) == token)
{
return true;
}
// if (goo) {
// Console.WriteLine();
// } |
// if (goo) {
// Console.WriteLine();
// } e|
if (token.IsKind(SyntaxKind.CloseBraceToken) && ifStatement.Statement is BlockSyntax && token == ((BlockSyntax)ifStatement.Statement).CloseBraceToken)
{
return true;
} }
return false; return false;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册