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

List patterns: main IDE scenarios and AddRequiredParens #53850

Merged
merged 15 commits into from
Oct 23, 2021
30 changes: 30 additions & 0 deletions src/Compilers/CSharp/Portable/Syntax/SyntaxNormalizer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -520,6 +520,29 @@ private static bool NeedsSeparatorForPositionalPattern(SyntaxToken token, Syntax
return false;
}

private static bool NeedsSeparatorForListPattern(SyntaxToken token, SyntaxToken next)
{
var listPattern = token.Parent as ListPatternSyntax ?? next.Parent as ListPatternSyntax;
if (listPattern == null)
{
return false;
}

// is$$[1, 2]
if (next.IsKind(SyntaxKind.OpenBracketToken))
{
return true;
}

// is [1, 2]$$list
if (token.IsKind(SyntaxKind.OpenBracketToken))
{
return listPattern.Designation is not null;
}

return false;
}

private static bool NeedsSeparator(SyntaxToken token, SyntaxToken next)
{
if (token.Parent == null || next.Parent == null)
Expand Down Expand Up @@ -806,15 +829,22 @@ private static bool NeedsSeparator(SyntaxToken token, SyntaxToken next)
case SyntaxKind.NotKeyword:
return true;
}

if (NeedsSeparatorForPropertyPattern(token, next))
{
return true;
}

if (NeedsSeparatorForPositionalPattern(token, next))
{
return true;
}

if (NeedsSeparatorForListPattern(token, next))
{
return true;
}

return false;
}

Expand Down
24 changes: 24 additions & 0 deletions src/Compilers/CSharp/Test/Syntax/Syntax/SyntaxNormalizerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,30 @@ DeliveryTruck t when (t.GrossWeightClass < 3000) => 10.00m - 2.00m,
TestNormalizeStatement(a, b);
}

[Fact]
public void TestNormalizeListPattern()
{
var text = "_ = this is[ 1,2,.. var rest ];";
var expected = @"_ = this is [1, 2, ..var rest];";
TestNormalizeStatement(text, expected);
}

[Fact]
public void TestNormalizeListPattern_TrailingComma()
{
var text = "_ = this is[ 1,2, 3,];";
var expected = @"_ = this is [1, 2, 3, ];";
TestNormalizeStatement(text, expected);
}

[Fact]
public void TestNormalizeListPattern_EmptyList()
{
var text = "_ = this is[];";
var expected = @"_ = this is [];";
TestNormalizeStatement(text, expected);
}

[Fact, WorkItem(50742, "https://github.com/dotnet/roslyn/issues/50742")]
public void TestLineBreakInterpolations()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,36 @@ public void Array_Nested()
CheckStart(session.Session);
}

[WpfFact, Trait(Traits.Feature, Traits.Features.AutomaticCompletion)]
public void ListPattern()
{
var code = @"
class C
{
void M(object o)
{
_ = o is $$
}
}
";
var expected = @"
class C
{
void M(object o)
{
_ = o is [
]
}
}
";
using var session = CreateSession(code);
CheckStart(session.Session);
// Open bracket probably should be moved to new line
// Close bracket probably should be aligned with open bracket
// Tracked by https://github.com/dotnet/roslyn/issues/57244
CheckReturn(session.Session, 0, expected);
}

internal static Holder CreateSession(string code)
{
return CreateSession(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4889,6 +4889,51 @@ await TestInMethodAsync(@"
Punctuation.Semicolon);
}

[Theory]
[CombinatorialData]
public async Task TestListPattern(TestHost testHost)
{
await TestInMethodAsync(@"
_ = new int[0] switch
{
case [1, 2]:
break;
case [1, .. var end]:
break;
}",
testHost,
Identifier("_"),
Operators.Equals,
Keyword("new"),
Keyword("int"),
Punctuation.OpenBracket,
Number("0"),
Punctuation.CloseBracket,
ControlKeyword("switch"),
Punctuation.OpenCurly,
Keyword("case"),
Punctuation.OpenBracket,
Number("1"),
Punctuation.Comma,
Number("2"),
Punctuation.CloseBracket,
Punctuation.Colon,
ControlKeyword("break"),
Punctuation.Semicolon,
Keyword("case"),
Punctuation.OpenBracket,
Number("1"),
Punctuation.Comma,
Punctuation.DotDot,
Identifier("var"),
Identifier("end"),
Punctuation.CloseBracket,
Punctuation.Colon,
ControlKeyword("break"),
Punctuation.Semicolon,
Punctuation.CloseCurly);
}

[Theory]
[CombinatorialData]
public async Task TestTupleTypeSyntax(TestHost testHost)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1352,6 +1352,29 @@ await AssertIndentNotUsingSmartTokenFormatterButUsingIndenterAsync(
expectedIndentation: 12);
}

[WpfFact]
[Trait(Traits.Feature, Traits.Features.SmartIndent)]
public async Task IndentListPattern()
{
var code = @"
class C
{
void Main(object o)
{
var y = o is
[

]
}
}";
// Expected indentation probably should be 12 instead
// Tracked by https://github.com/dotnet/roslyn/issues/57244
await AssertIndentNotUsingSmartTokenFormatterButUsingIndenterAsync(
code,
indentationLine: 7,
expectedIndentation: 8);
}

[Trait(Traits.Feature, Traits.Features.SmartIndent)]
[WpfTheory]
[InlineData("x", "is < 7 and (>= 3 or > 50) or not <= 0;", 12)]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7492,6 +7492,70 @@ void M2()
MainDescription($"({FeaturesResources.local_variable}) string? x"));
}

[Fact, Trait(Traits.Feature, Traits.Features.QuickInfo)]
public async Task TestVarPatternOnVarKeyword_InListPattern()
{
await TestAsync(
@"class C
{
void M(char[] array)
{
if (array is [ va$$r one ])
{
}
}
}",
MainDescription("struct System.Char"));
}

[Fact, Trait(Traits.Feature, Traits.Features.QuickInfo)]
public async Task TestVarPatternOnVariableItself_InListPattern()
{
await TestAsync(
@"class C
{
void M(char[] array)
{
if (array is [ var o$$ne ])
{
}
}
}",
MainDescription($"({FeaturesResources.local_variable}) char one"));
}

[Fact, Trait(Traits.Feature, Traits.Features.QuickInfo)]
public async Task TestVarPatternOnVarKeyword_InSlicePattern()
{
await TestAsync(
@"class C
{
void M(char[] array)
{
if (array is [..va$$r one ])
{
}
}
}",
MainDescription("char[]"));
}

[Fact, Trait(Traits.Feature, Traits.Features.QuickInfo)]
public async Task TestVarPatternOnVariableItself_InSlicePattern()
{
await TestAsync(
@"class C
{
void M(char[] array)
{
if (array is [ ..var o$$ne ])
{
}
}
}",
MainDescription($"({FeaturesResources.local_variable}) char[]? one"));
}

[WorkItem(53135, "https://github.com/dotnet/roslyn/issues/53135")]
[Fact, Trait(Traits.Feature, Traits.Features.QuickInfo)]
public async Task TestDocumentationCData()
Expand Down
Loading