/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Workspaces/CSharpTest/Formatting/FormattingTests_Patterns.cs
687 строк
22 KB
Copilot
Fix property pattern indentation in positional and parenthesized patterns (#81199)
14 ноя 2025, 20:12
Не верифицирован
14 ноя 2025, 20:12
4bc2a24
Код
Авторство
О чём код?
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. #nullable disable using System.Threading.Tasks; using Microsoft.CodeAnalysis.CSharp.Formatting; using Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions; using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; using Xunit; namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Formatting; [Trait(Traits.Feature, Traits.Features.Formatting)] public sealed class FormattingTests_Patterns : CSharpFormattingTestBase { [Theory, CombinatorialData] public async Task FormatRelationalPatterns1( [CombinatorialValues("<", "<=", ">", ">=")] string operatorText, BinaryOperatorSpacingOptions spacing) { var expectedSingle = $$""" class A { bool Method(int value) { return value is {{operatorText}} 3 or {{operatorText}} 5; } } """; var expectedIgnore = $$""" class A { bool Method(int value) { return value is {{operatorText}} 3 or {{operatorText}} 5; } } """; var expectedRemove = $$""" class A { bool Method(int value) { return value is {{operatorText}}3 or {{operatorText}}5; } } """; var expected = spacing switch { BinaryOperatorSpacingOptions.Single => expectedSingle, BinaryOperatorSpacingOptions.Ignore => expectedIgnore, BinaryOperatorSpacingOptions.Remove => expectedRemove, _ => throw ExceptionUtilities.Unreachable(), }; var changingOptions = new OptionsCollection(LanguageNames.CSharp) { { CSharpFormattingOptions2.SpacingAroundBinaryOperator, spacing }, }; await AssertFormatAsync(expected, $$""" class A { bool Method(int value) { return value is {{operatorText}} 3 or {{operatorText}} 5; } } """, changedOptionSet: changingOptions); } [Theory, CombinatorialData] public async Task FormatRelationalPatterns2( [CombinatorialValues("<", "<=", ">", ">=")] string operatorText, BinaryOperatorSpacingOptions spacing, bool spaceWithinExpressionParentheses) { var expectedSingleFalse = $$""" class A { bool Method(int value) { return value is ({{operatorText}} 3) or ({{operatorText}} 5); } } """; var expectedIgnoreFalse = $$""" class A { bool Method(int value) { return value is ({{operatorText}} 3) or ({{operatorText}} 5); } } """; var expectedRemoveFalse = $$""" class A { bool Method(int value) { return value is ({{operatorText}}3) or ({{operatorText}}5); } } """; var expectedSingleTrue = $$""" class A { bool Method(int value) { return value is ( {{operatorText}} 3 ) or ( {{operatorText}} 5 ); } } """; var expectedIgnoreTrue = $$""" class A { bool Method(int value) { return value is ( {{operatorText}} 3 ) or ( {{operatorText}} 5 ); } } """; var expectedRemoveTrue = $$""" class A { bool Method(int value) { return value is ( {{operatorText}}3 ) or ( {{operatorText}}5 ); } } """; var expected = (spacing, spaceWithinExpressionParentheses) switch { (BinaryOperatorSpacingOptions.Single, false) => expectedSingleFalse, (BinaryOperatorSpacingOptions.Ignore, false) => expectedIgnoreFalse, (BinaryOperatorSpacingOptions.Remove, false) => expectedRemoveFalse, (BinaryOperatorSpacingOptions.Single, true) => expectedSingleTrue, (BinaryOperatorSpacingOptions.Ignore, true) => expectedIgnoreTrue, (BinaryOperatorSpacingOptions.Remove, true) => expectedRemoveTrue, _ => throw ExceptionUtilities.Unreachable(), }; var changingOptions = new OptionsCollection(LanguageNames.CSharp) { { CSharpFormattingOptions2.SpacingAroundBinaryOperator, spacing }, { CSharpFormattingOptions2.SpaceBetweenParentheses, CSharpFormattingOptions2.SpaceBetweenParentheses.DefaultValue.WithFlagValue(SpacePlacementWithinParentheses.Expressions, spaceWithinExpressionParentheses) }, }; await AssertFormatAsync(expected, $$""" class A { bool Method(int value) { return value is ( {{operatorText}} 3 ) or ( {{operatorText}} 5 ) ; } } """, changedOptionSet: changingOptions); } [Theory, CombinatorialData] public async Task FormatNotPatterns1(BinaryOperatorSpacingOptions spacing) { var expectedSingle = $$""" class A { bool Method(int value) { return value is not 3 or not 5; } } """; var expectedIgnore = $$""" class A { bool Method(int value) { return value is not 3 or not 5; } } """; var expectedRemove = $$""" class A { bool Method(int value) { return value is not 3 or not 5; } } """; var expected = spacing switch { BinaryOperatorSpacingOptions.Single => expectedSingle, BinaryOperatorSpacingOptions.Ignore => expectedIgnore, BinaryOperatorSpacingOptions.Remove => expectedRemove, _ => throw ExceptionUtilities.Unreachable(), }; var changingOptions = new OptionsCollection(LanguageNames.CSharp) { { CSharpFormattingOptions2.SpacingAroundBinaryOperator, spacing }, }; await AssertFormatAsync(expected, $$""" class A { bool Method(int value) { return value is not 3 or not 5; } } """, changedOptionSet: changingOptions); } [Theory, CombinatorialData] public async Task FormatNotPatterns2( BinaryOperatorSpacingOptions spacing, bool spaceWithinExpressionParentheses) { var expectedSingleFalse = $$""" class A { bool Method(int value) { return value is (not 3) or (not 5); } } """; var expectedIgnoreFalse = $$""" class A { bool Method(int value) { return value is (not 3) or (not 5); } } """; var expectedRemoveFalse = $$""" class A { bool Method(int value) { return value is (not 3) or (not 5); } } """; var expectedSingleTrue = $$""" class A { bool Method(int value) { return value is ( not 3 ) or ( not 5 ); } } """; var expectedIgnoreTrue = $$""" class A { bool Method(int value) { return value is ( not 3 ) or ( not 5 ); } } """; var expectedRemoveTrue = $$""" class A { bool Method(int value) { return value is ( not 3 ) or ( not 5 ); } } """; var expected = (spacing, spaceWithinExpressionParentheses) switch { (BinaryOperatorSpacingOptions.Single, false) => expectedSingleFalse, (BinaryOperatorSpacingOptions.Ignore, false) => expectedIgnoreFalse, (BinaryOperatorSpacingOptions.Remove, false) => expectedRemoveFalse, (BinaryOperatorSpacingOptions.Single, true) => expectedSingleTrue, (BinaryOperatorSpacingOptions.Ignore, true) => expectedIgnoreTrue, (BinaryOperatorSpacingOptions.Remove, true) => expectedRemoveTrue, _ => throw ExceptionUtilities.Unreachable(), }; var changingOptions = new OptionsCollection(LanguageNames.CSharp) { { CSharpFormattingOptions2.SpacingAroundBinaryOperator, spacing }, { CSharpFormattingOptions2.SpaceBetweenParentheses, CSharpFormattingOptions2.SpaceBetweenParentheses.DefaultValue.WithFlagValue(SpacePlacementWithinParentheses.Expressions, spaceWithinExpressionParentheses) }, }; await AssertFormatAsync(expected, $$""" class A { bool Method(int value) { return value is ( not 3 ) or ( not 5 ); } } """, changedOptionSet: changingOptions); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/46284")] public Task FormatMultiLinePattern1() => AssertFormatAsync(""" class TypeName { bool MethodName(string value) { return value is object && value is { Length: 2, }; } } """, """ class TypeName { bool MethodName(string value) { return value is object && value is { Length: 2, }; } } """); [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/46284")] public Task FormatMultiLinePattern2() => AssertFormatAsync(""" class TypeName { private static bool IsCallingConventionModifier(CustomModifier modifier) { var modifierType = ((CSharpCustomModifier)modifier).ModifierSymbol; return (object)modifierType.ContainingAssembly == modifierType.ContainingAssembly.CorLibrary && modifierType.Name != "CallConv" && modifierType.Arity == 0 && modifierType.Name.StartsWith("CallConv", StringComparison.Ordinal) && modifierType.ContainingNamespace is { Name: "CompilerServices", ContainingNamespace: { Name: "Runtime", ContainingNamespace: { Name: "System", ContainingNamespace: { IsGlobalNamespace: true } } } }; } } """, """ class TypeName { private static bool IsCallingConventionModifier(CustomModifier modifier) { var modifierType = ((CSharpCustomModifier)modifier).ModifierSymbol; return (object)modifierType.ContainingAssembly == modifierType.ContainingAssembly.CorLibrary && modifierType.Name != "CallConv" && modifierType.Arity == 0 && modifierType.Name.StartsWith("CallConv", StringComparison.Ordinal) && modifierType.ContainingNamespace is { Name: "CompilerServices", ContainingNamespace: { Name: "Runtime", ContainingNamespace: { Name: "System", ContainingNamespace: { IsGlobalNamespace: true } } } }; } } """); [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/46284")] public Task FormatMultiLinePattern3() => AssertFormatAsync(""" class TypeName { private static bool IsCallingConventionModifier(CustomModifier modifier) { var modifierType = ((CSharpCustomModifier)modifier).ModifierSymbol; return (object)modifierType.ContainingAssembly == modifierType.ContainingAssembly.CorLibrary && modifierType.Name != "CallConv" && modifierType.Arity == 0 && modifierType.Name.StartsWith("CallConv", StringComparison.Ordinal) && modifierType.ContainingNamespace is { Name: "CompilerServices", ContainingNamespace: { Name: "Runtime", ContainingNamespace: { Name: "System", ContainingNamespace: { IsGlobalNamespace: true } } } }; } } """, """ class TypeName { private static bool IsCallingConventionModifier(CustomModifier modifier) { var modifierType = ((CSharpCustomModifier)modifier).ModifierSymbol; return (object)modifierType.ContainingAssembly == modifierType.ContainingAssembly.CorLibrary && modifierType.Name != "CallConv" && modifierType.Arity == 0 && modifierType.Name.StartsWith("CallConv", StringComparison.Ordinal) && modifierType.ContainingNamespace is { Name: "CompilerServices", ContainingNamespace: { Name: "Runtime", ContainingNamespace: { Name: "System", ContainingNamespace: { IsGlobalNamespace: true } } } }; } } """); [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/42861")] public Task FormatMultiLinePattern4() => AssertFormatAsync(""" class TypeName { void MethodName(string value) { if (value is { Length: 2, }) { } } } """, """ class TypeName { void MethodName(string value) { if (value is { Length: 2, }) { } } } """); [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/42861")] public Task FormatMultiLinePattern5() => AssertFormatAsync(""" class TypeName { void MethodName(string value) { while (value is { Length: 2, }) { } } } """, """ class TypeName { void MethodName(string value) { while (value is { Length: 2, }) { } } } """); [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/42861")] public Task FormatNestedListPattern1() => AssertFormatAsync(""" class C { void M(string[] ss) { if (ss is [[]]) { } } } """, """ class C { void M(string[] ss) { if (ss is [ [ ] ]) { } } } """); [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/42861")] public Task FormatNestedListPattern2() => AssertFormatAsync(""" class C { void M(string[] ss) { if (ss is [[], []]) { } } } """, """ class C { void M(string[] ss) { if (ss is [ [ ],[ ] ]) { } } } """); [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/42861")] public Task FormatNestedListPattern3() => AssertFormatAsync(""" class C { void M(string[] ss) { if (ss is [[], [], []]) { } } } """, """ class C { void M(string[] ss) { if (ss is [ [ ],[ ] , [ ] ] ) { } } } """); [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/42861")] public Task FormatNestedListPattern4() => AssertFormatAsync(""" class C { void M(string[][] ss) { if (ss is [[[]]]) { } } } """, """ class C { void M(string[][] ss) { if (ss is [ [ [ ] ] ] ) { } } } """); [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/78449")] public Task FormatParenthesizedPatternWithMultiplePatterns() => AssertFormatAsync(""" public class Goo { public bool DoThing(Exception input) { if (input is not ( { InnerException: null } or { Data: not null } )) { return false; } } } """, """ public class Goo { public bool DoThing(Exception input) { if (input is not ( { InnerException: null } or { Data: not null } )) { return false; } } } """); [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/54434")] public Task FormatPositionPattern1() => AssertFormatAsync(""" public class Goo { public void DoThing() { OrderingSyntax former = orderings[i], latter = orderings[j]; if ((former, latter) is not ( { Expression: IdentifierNameSyntax { Identifier: { ValueText: var formerIdentifier } } }, { Expression: IdentifierNameSyntax { Identifier: { ValueText: var latterIdentifier } } })) { continue; } } } """, """ public class Goo { public void DoThing() { OrderingSyntax former = orderings[i], latter = orderings[j]; if ((former, latter) is not ( { Expression: IdentifierNameSyntax { Identifier: { ValueText: var formerIdentifier } } }, { Expression: IdentifierNameSyntax { Identifier: { ValueText: var latterIdentifier } } })) { continue; } } } """); }